Merge lp:~dobey/ubuntu/natty/ubuntuone-control-panel/release-0-8-3 into lp:ubuntu/natty/ubuntuone-control-panel
- Natty (11.04)
- release-0-8-3
- Merge into natty
Proposed by
dobey
Status: | Merged |
---|---|
Merged at revision: | 12 |
Proposed branch: | lp:~dobey/ubuntu/natty/ubuntuone-control-panel/release-0-8-3 |
Merge into: | lp:ubuntu/natty/ubuntuone-control-panel |
Diff against target: |
2036 lines (+930/-264) 19 files modified
PKG-INFO (+23/-1) data/device.ui (+1/-1) data/management.ui (+3/-29) data/overview.ui (+235/-68) data/volumes.ui (+22/-19) debian/changelog (+17/-0) debian/python-ubuntuone-control-panel.install (+4/-1) debian/ubuntuone-control-panel-gtk.install (+2/-1) setup.py (+2/-1) ubuntuone-control-panel-gtk.desktop.in (+1/-0) ubuntuone.controlpanel.pth (+2/-0) ubuntuone/controlpanel/backend.py (+56/-8) ubuntuone/controlpanel/dbus_client.py (+43/-2) ubuntuone/controlpanel/gtk/gui.py (+60/-61) ubuntuone/controlpanel/gtk/tests/__init__.py (+2/-2) ubuntuone/controlpanel/gtk/tests/test_gui.py (+47/-41) ubuntuone/controlpanel/integrationtests/test_dbus_client_sd.py (+184/-4) ubuntuone/controlpanel/tests/__init__.py (+79/-3) ubuntuone/controlpanel/tests/test_backend.py (+147/-22) |
To merge this branch: | bzr merge lp:~dobey/ubuntu/natty/ubuntuone-control-panel/release-0-8-3 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ken VanDine | Approve | ||
Review via email: mp+49491@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'PKG-INFO' | |||
2 | --- PKG-INFO 2011-02-04 20:02:28 +0000 | |||
3 | +++ PKG-INFO 2011-02-12 03:22:55 +0000 | |||
4 | @@ -1,6 +1,6 @@ | |||
5 | 1 | Metadata-Version: 1.1 | 1 | Metadata-Version: 1.1 |
6 | 2 | Name: ubuntuone-control-panel | 2 | Name: ubuntuone-control-panel |
8 | 3 | Version: 0.8.2 | 3 | Version: 0.8.3 |
9 | 4 | Summary: Ubuntu One Control Panel | 4 | Summary: Ubuntu One Control Panel |
10 | 5 | Home-page: https://launchpad.net/ubuntuone-control-panel | 5 | Home-page: https://launchpad.net/ubuntuone-control-panel |
11 | 6 | Author: Natalia Bidart | 6 | Author: Natalia Bidart |
12 | @@ -8,4 +8,26 @@ | |||
13 | 8 | License: GPL v3 | 8 | License: GPL v3 |
14 | 9 | Description: Application to manage a Ubuntu One account. Provides aDBus service to query/modify all the Ubuntu One bits. | 9 | Description: Application to manage a Ubuntu One account. Provides aDBus service to query/modify all the Ubuntu One bits. |
15 | 10 | Platform: UNKNOWN | 10 | Platform: UNKNOWN |
16 | 11 | Requires: apt | ||
17 | 12 | Requires: aptdaemon | ||
18 | 13 | Requires: dbus | ||
19 | 14 | Requires: defer | ||
20 | 15 | Requires: desktopcouch.application.replication_services | ||
21 | 16 | Requires: gi.repository | ||
22 | 17 | Requires: gobject | ||
23 | 18 | Requires: gtk | ||
24 | 19 | Requires: mocker | ||
25 | 20 | Requires: oauth | ||
26 | 21 | Requires: pango | ||
27 | 22 | Requires: simplejson | ||
28 | 23 | Requires: twisted.application | ||
29 | 24 | Requires: twisted.internet | ||
30 | 25 | Requires: twisted.python.failure | ||
31 | 26 | Requires: twisted.web | ||
32 | 27 | Requires: ubuntu_sso | ||
33 | 28 | Requires: ubuntuone.clientdefs | ||
34 | 29 | Requires: ubuntuone.devtools.handlers | ||
35 | 30 | Requires: ubuntuone.devtools.testcase | ||
36 | 31 | Requires: ubuntuone.logger | ||
37 | 32 | Requires: ubuntuone.platform.linux | ||
38 | 11 | Provides: ubuntuone.controlpanel | 33 | Provides: ubuntuone.controlpanel |
39 | 12 | 34 | ||
40 | === added file 'data/contacts.png' | |||
41 | 13 | Binary files data/contacts.png 1970-01-01 00:00:00 +0000 and data/contacts.png 2011-02-12 03:22:55 +0000 differ | 35 | Binary files data/contacts.png 1970-01-01 00:00:00 +0000 and data/contacts.png 2011-02-12 03:22:55 +0000 differ |
42 | === modified file 'data/device.ui' | |||
43 | --- data/device.ui 2011-01-25 19:08:59 +0000 | |||
44 | +++ data/device.ui 2011-02-12 03:22:55 +0000 | |||
45 | @@ -154,7 +154,7 @@ | |||
46 | 154 | <child> | 154 | <child> |
47 | 155 | <object class="GtkVButtonBox" id="vbuttonbox1"> | 155 | <object class="GtkVButtonBox" id="vbuttonbox1"> |
48 | 156 | <property name="visible">True</property> | 156 | <property name="visible">True</property> |
50 | 157 | <property name="layout_style">center</property> | 157 | <property name="layout_style">start</property> |
51 | 158 | <child> | 158 | <child> |
52 | 159 | <object class="GtkButton" id="remove"> | 159 | <object class="GtkButton" id="remove"> |
53 | 160 | <property name="label">gtk-remove</property> | 160 | <property name="label">gtk-remove</property> |
54 | 161 | 161 | ||
55 | === added file 'data/files.png' | |||
56 | 162 | Binary files data/files.png 1970-01-01 00:00:00 +0000 and data/files.png 2011-02-12 03:22:55 +0000 differ | 162 | Binary files data/files.png 1970-01-01 00:00:00 +0000 and data/files.png 2011-02-12 03:22:55 +0000 differ |
57 | === modified file 'data/management.ui' | |||
58 | --- data/management.ui 2011-01-25 19:08:59 +0000 | |||
59 | +++ data/management.ui 2011-02-12 03:22:55 +0000 | |||
60 | @@ -20,25 +20,14 @@ | |||
61 | 20 | <property name="border_width">10</property> | 20 | <property name="border_width">10</property> |
62 | 21 | <property name="spacing">10</property> | 21 | <property name="spacing">10</property> |
63 | 22 | <child> | 22 | <child> |
65 | 23 | <object class="GtkHBox" id="quota_box"> | 23 | <object class="GtkVBox" id="quota_box"> |
66 | 24 | <property name="visible">True</property> | 24 | <property name="visible">True</property> |
68 | 25 | <property name="can_focus">False</property> | 25 | <property name="spacing">5</property> |
69 | 26 | <child> | 26 | <child> |
71 | 27 | <object class="GtkAlignment" id="alignment1"> | 27 | <object class="GtkProgressBar" id="quota_progressbar"> |
72 | 28 | <property name="visible">True</property> | 28 | <property name="visible">True</property> |
73 | 29 | <property name="can_focus">False</property> | ||
74 | 30 | <property name="xscale">0</property> | ||
75 | 31 | <property name="yscale">0</property> | ||
76 | 32 | <child> | ||
77 | 33 | <object class="GtkProgressBar" id="quota_progressbar"> | ||
78 | 34 | <property name="visible">True</property> | ||
79 | 35 | <property name="can_focus">False</property> | ||
80 | 36 | </object> | ||
81 | 37 | </child> | ||
82 | 38 | </object> | 29 | </object> |
83 | 39 | <packing> | 30 | <packing> |
84 | 40 | <property name="expand">True</property> | ||
85 | 41 | <property name="fill">True</property> | ||
86 | 42 | <property name="position">0</property> | 31 | <property name="position">0</property> |
87 | 43 | </packing> | 32 | </packing> |
88 | 44 | </child> | 33 | </child> |
89 | @@ -117,7 +106,6 @@ | |||
90 | 117 | <property name="label" translatable="yes">Shares</property> | 106 | <property name="label" translatable="yes">Shares</property> |
91 | 118 | <property name="can_focus">True</property> | 107 | <property name="can_focus">True</property> |
92 | 119 | <property name="receives_default">False</property> | 108 | <property name="receives_default">False</property> |
93 | 120 | <property name="use_action_appearance">False</property> | ||
94 | 121 | <property name="draw_indicator">False</property> | 109 | <property name="draw_indicator">False</property> |
95 | 122 | <property name="group">dashboard_button</property> | 110 | <property name="group">dashboard_button</property> |
96 | 123 | </object> | 111 | </object> |
97 | @@ -133,7 +121,6 @@ | |||
98 | 133 | <property name="visible">True</property> | 121 | <property name="visible">True</property> |
99 | 134 | <property name="can_focus">True</property> | 122 | <property name="can_focus">True</property> |
100 | 135 | <property name="receives_default">False</property> | 123 | <property name="receives_default">False</property> |
101 | 136 | <property name="use_action_appearance">False</property> | ||
102 | 137 | <property name="draw_indicator">False</property> | 124 | <property name="draw_indicator">False</property> |
103 | 138 | <property name="group">dashboard_button</property> | 125 | <property name="group">dashboard_button</property> |
104 | 139 | </object> | 126 | </object> |
105 | @@ -148,7 +135,6 @@ | |||
106 | 148 | <property name="label" translatable="yes">Services</property> | 135 | <property name="label" translatable="yes">Services</property> |
107 | 149 | <property name="can_focus">True</property> | 136 | <property name="can_focus">True</property> |
108 | 150 | <property name="receives_default">False</property> | 137 | <property name="receives_default">False</property> |
109 | 151 | <property name="use_action_appearance">False</property> | ||
110 | 152 | <property name="draw_indicator">False</property> | 138 | <property name="draw_indicator">False</property> |
111 | 153 | <property name="group">dashboard_button</property> | 139 | <property name="group">dashboard_button</property> |
112 | 154 | </object> | 140 | </object> |
113 | @@ -161,44 +147,36 @@ | |||
114 | 161 | </object> | 147 | </object> |
115 | 162 | <packing> | 148 | <packing> |
116 | 163 | <property name="expand">False</property> | 149 | <property name="expand">False</property> |
117 | 164 | <property name="fill">True</property> | ||
118 | 165 | <property name="position">1</property> | 150 | <property name="position">1</property> |
119 | 166 | </packing> | 151 | </packing> |
120 | 167 | </child> | 152 | </child> |
121 | 168 | <child> | 153 | <child> |
122 | 169 | <object class="GtkHSeparator" id="hseparator2"> | 154 | <object class="GtkHSeparator" id="hseparator2"> |
123 | 170 | <property name="visible">True</property> | 155 | <property name="visible">True</property> |
124 | 171 | <property name="can_focus">False</property> | ||
125 | 172 | </object> | 156 | </object> |
126 | 173 | <packing> | 157 | <packing> |
127 | 174 | <property name="expand">True</property> | ||
128 | 175 | <property name="fill">True</property> | ||
129 | 176 | <property name="position">2</property> | 158 | <property name="position">2</property> |
130 | 177 | </packing> | 159 | </packing> |
131 | 178 | </child> | 160 | </child> |
132 | 179 | </object> | 161 | </object> |
133 | 180 | <packing> | 162 | <packing> |
134 | 181 | <property name="expand">False</property> | 163 | <property name="expand">False</property> |
135 | 182 | <property name="fill">True</property> | ||
136 | 183 | <property name="position">0</property> | 164 | <property name="position">0</property> |
137 | 184 | </packing> | 165 | </packing> |
138 | 185 | </child> | 166 | </child> |
139 | 186 | <child> | 167 | <child> |
140 | 187 | <object class="GtkImage" id="image1"> | 168 | <object class="GtkImage" id="image1"> |
141 | 188 | <property name="visible">True</property> | 169 | <property name="visible">True</property> |
142 | 189 | <property name="can_focus">False</property> | ||
143 | 190 | <property name="pixbuf">banner.png</property> | 170 | <property name="pixbuf">banner.png</property> |
144 | 191 | </object> | 171 | </object> |
145 | 192 | <packing> | 172 | <packing> |
146 | 193 | <property name="expand">False</property> | 173 | <property name="expand">False</property> |
147 | 194 | <property name="fill">True</property> | ||
148 | 195 | <property name="position">1</property> | 174 | <property name="position">1</property> |
149 | 196 | </packing> | 175 | </packing> |
150 | 197 | </child> | 176 | </child> |
151 | 198 | </object> | 177 | </object> |
152 | 199 | <packing> | 178 | <packing> |
153 | 200 | <property name="expand">False</property> | 179 | <property name="expand">False</property> |
154 | 201 | <property name="fill">True</property> | ||
155 | 202 | <property name="position">1</property> | 180 | <property name="position">1</property> |
156 | 203 | </packing> | 181 | </packing> |
157 | 204 | </child> | 182 | </child> |
158 | @@ -207,21 +185,17 @@ | |||
159 | 207 | </object> | 185 | </object> |
160 | 208 | <packing> | 186 | <packing> |
161 | 209 | <property name="expand">False</property> | 187 | <property name="expand">False</property> |
162 | 210 | <property name="fill">True</property> | ||
163 | 211 | <property name="position">0</property> | 188 | <property name="position">0</property> |
164 | 212 | </packing> | 189 | </packing> |
165 | 213 | </child> | 190 | </child> |
166 | 214 | <child> | 191 | <child> |
167 | 215 | <object class="GtkNotebook" id="notebook"> | 192 | <object class="GtkNotebook" id="notebook"> |
168 | 216 | <property name="visible">True</property> | 193 | <property name="visible">True</property> |
169 | 217 | <property name="can_focus">False</property> | ||
170 | 218 | <property name="show_tabs">False</property> | 194 | <property name="show_tabs">False</property> |
171 | 219 | <property name="show_border">False</property> | 195 | <property name="show_border">False</property> |
172 | 220 | <property name="homogeneous">True</property> | 196 | <property name="homogeneous">True</property> |
173 | 221 | </object> | 197 | </object> |
174 | 222 | <packing> | 198 | <packing> |
175 | 223 | <property name="expand">True</property> | ||
176 | 224 | <property name="fill">True</property> | ||
177 | 225 | <property name="position">1</property> | 199 | <property name="position">1</property> |
178 | 226 | </packing> | 200 | </packing> |
179 | 227 | </child> | 201 | </child> |
180 | 228 | 202 | ||
181 | === added file 'data/music.png' | |||
182 | 229 | Binary files data/music.png 1970-01-01 00:00:00 +0000 and data/music.png 2011-02-12 03:22:55 +0000 differ | 203 | Binary files data/music.png 1970-01-01 00:00:00 +0000 and data/music.png 2011-02-12 03:22:55 +0000 differ |
183 | === added file 'data/notes.png' | |||
184 | 230 | Binary files data/notes.png 1970-01-01 00:00:00 +0000 and data/notes.png 2011-02-12 03:22:55 +0000 differ | 204 | Binary files data/notes.png 1970-01-01 00:00:00 +0000 and data/notes.png 2011-02-12 03:22:55 +0000 differ |
185 | === modified file 'data/overview.ui' | |||
186 | --- data/overview.ui 2011-01-25 19:08:59 +0000 | |||
187 | +++ data/overview.ui 2011-02-12 03:22:55 +0000 | |||
188 | @@ -4,74 +4,263 @@ | |||
189 | 4 | <!-- interface-naming-policy project-wide --> | 4 | <!-- interface-naming-policy project-wide --> |
190 | 5 | <object class="GtkVBox" id="itself"> | 5 | <object class="GtkVBox" id="itself"> |
191 | 6 | <property name="visible">True</property> | 6 | <property name="visible">True</property> |
192 | 7 | <property name="can_focus">False</property> | ||
193 | 7 | <child> | 8 | <child> |
195 | 8 | <object class="GtkImage" id="image"> | 9 | <object class="GtkEventBox" id="header"> |
196 | 9 | <property name="visible">True</property> | 10 | <property name="visible">True</property> |
198 | 10 | <property name="pixbuf">overview.png</property> | 11 | <property name="can_focus">False</property> |
199 | 12 | <child> | ||
200 | 13 | <object class="GtkImage" id="image"> | ||
201 | 14 | <property name="visible">True</property> | ||
202 | 15 | <property name="can_focus">False</property> | ||
203 | 16 | <property name="pixbuf">overview.png</property> | ||
204 | 17 | </object> | ||
205 | 18 | </child> | ||
206 | 11 | </object> | 19 | </object> |
207 | 12 | <packing> | 20 | <packing> |
208 | 13 | <property name="expand">False</property> | 21 | <property name="expand">False</property> |
209 | 22 | <property name="fill">True</property> | ||
210 | 14 | <property name="position">0</property> | 23 | <property name="position">0</property> |
211 | 15 | </packing> | 24 | </packing> |
212 | 16 | </child> | 25 | </child> |
213 | 17 | <child> | 26 | <child> |
215 | 18 | <object class="GtkAlignment" id="alignment1"> | 27 | <object class="GtkScrolledWindow" id="scrolledwindow1"> |
216 | 19 | <property name="visible">True</property> | 28 | <property name="visible">True</property> |
218 | 20 | <property name="yscale">0</property> | 29 | <property name="can_focus">True</property> |
219 | 30 | <property name="hscrollbar_policy">automatic</property> | ||
220 | 31 | <property name="vscrollbar_policy">automatic</property> | ||
221 | 21 | <child> | 32 | <child> |
223 | 22 | <object class="GtkHBox" id="hbox1"> | 33 | <object class="GtkViewport" id="viewport1"> |
224 | 23 | <property name="visible">True</property> | 34 | <property name="visible">True</property> |
227 | 24 | <property name="border_width">20</property> | 35 | <property name="can_focus">False</property> |
228 | 25 | <property name="spacing">5</property> | 36 | <property name="shadow_type">none</property> |
229 | 26 | <child> | 37 | <child> |
231 | 27 | <object class="GtkVBox" id="messages"> | 38 | <object class="GtkHBox" id="hbox1"> |
232 | 28 | <property name="visible">True</property> | 39 | <property name="visible">True</property> |
234 | 29 | <property name="spacing">10</property> | 40 | <property name="can_focus">False</property> |
235 | 41 | <property name="border_width">20</property> | ||
236 | 42 | <property name="spacing">5</property> | ||
237 | 30 | <child> | 43 | <child> |
239 | 31 | <placeholder/> | 44 | <object class="GtkTable" id="table1"> |
240 | 45 | <property name="visible">True</property> | ||
241 | 46 | <property name="can_focus">False</property> | ||
242 | 47 | <property name="n_rows">4</property> | ||
243 | 48 | <property name="n_columns">2</property> | ||
244 | 49 | <property name="column_spacing">10</property> | ||
245 | 50 | <property name="row_spacing">10</property> | ||
246 | 51 | <child> | ||
247 | 52 | <object class="GtkImage" id="image1"> | ||
248 | 53 | <property name="visible">True</property> | ||
249 | 54 | <property name="can_focus">False</property> | ||
250 | 55 | <property name="pixbuf">files.png</property> | ||
251 | 56 | </object> | ||
252 | 57 | <packing> | ||
253 | 58 | <property name="x_options">GTK_FILL</property> | ||
254 | 59 | <property name="y_options">GTK_FILL</property> | ||
255 | 60 | </packing> | ||
256 | 61 | </child> | ||
257 | 62 | <child> | ||
258 | 63 | <object class="GtkImage" id="image2"> | ||
259 | 64 | <property name="visible">True</property> | ||
260 | 65 | <property name="can_focus">False</property> | ||
261 | 66 | <property name="pixbuf">contacts.png</property> | ||
262 | 67 | </object> | ||
263 | 68 | <packing> | ||
264 | 69 | <property name="top_attach">1</property> | ||
265 | 70 | <property name="bottom_attach">2</property> | ||
266 | 71 | <property name="x_options">GTK_FILL</property> | ||
267 | 72 | <property name="y_options">GTK_FILL</property> | ||
268 | 73 | </packing> | ||
269 | 74 | </child> | ||
270 | 75 | <child> | ||
271 | 76 | <object class="GtkImage" id="image3"> | ||
272 | 77 | <property name="visible">True</property> | ||
273 | 78 | <property name="can_focus">False</property> | ||
274 | 79 | <property name="pixbuf">music.png</property> | ||
275 | 80 | </object> | ||
276 | 81 | <packing> | ||
277 | 82 | <property name="top_attach">2</property> | ||
278 | 83 | <property name="bottom_attach">3</property> | ||
279 | 84 | <property name="x_options">GTK_FILL</property> | ||
280 | 85 | <property name="y_options">GTK_FILL</property> | ||
281 | 86 | </packing> | ||
282 | 87 | </child> | ||
283 | 88 | <child> | ||
284 | 89 | <object class="GtkImage" id="image4"> | ||
285 | 90 | <property name="visible">True</property> | ||
286 | 91 | <property name="can_focus">False</property> | ||
287 | 92 | <property name="pixbuf">notes.png</property> | ||
288 | 93 | </object> | ||
289 | 94 | <packing> | ||
290 | 95 | <property name="top_attach">3</property> | ||
291 | 96 | <property name="bottom_attach">4</property> | ||
292 | 97 | <property name="x_options">GTK_FILL</property> | ||
293 | 98 | <property name="y_options">GTK_FILL</property> | ||
294 | 99 | </packing> | ||
295 | 100 | </child> | ||
296 | 101 | <child> | ||
297 | 102 | <object class="GtkLabel" id="label3"> | ||
298 | 103 | <property name="visible">True</property> | ||
299 | 104 | <property name="can_focus">False</property> | ||
300 | 105 | <property name="xalign">0</property> | ||
301 | 106 | <property name="label" translatable="yes">Files Anywhere | ||
302 | 107 | <span foreground="#909090">Backup and access your files from Windows, Ubuntu, or Mobile</span></property> | ||
303 | 108 | <property name="use_markup">True</property> | ||
304 | 109 | <property name="wrap">True</property> | ||
305 | 110 | </object> | ||
306 | 111 | <packing> | ||
307 | 112 | <property name="left_attach">1</property> | ||
308 | 113 | <property name="right_attach">2</property> | ||
309 | 114 | </packing> | ||
310 | 115 | </child> | ||
311 | 116 | <child> | ||
312 | 117 | <object class="GtkLabel" id="label4"> | ||
313 | 118 | <property name="visible">True</property> | ||
314 | 119 | <property name="can_focus">False</property> | ||
315 | 120 | <property name="xalign">0</property> | ||
316 | 121 | <property name="label" translatable="yes">Keep connected | ||
317 | 122 | <span foreground="#909090">Unify your contacts accress Desktop, Mobile and Web</span></property> | ||
318 | 123 | <property name="use_markup">True</property> | ||
319 | 124 | <property name="wrap">True</property> | ||
320 | 125 | </object> | ||
321 | 126 | <packing> | ||
322 | 127 | <property name="left_attach">1</property> | ||
323 | 128 | <property name="right_attach">2</property> | ||
324 | 129 | <property name="top_attach">1</property> | ||
325 | 130 | <property name="bottom_attach">2</property> | ||
326 | 131 | </packing> | ||
327 | 132 | </child> | ||
328 | 133 | <child> | ||
329 | 134 | <object class="GtkLabel" id="label5"> | ||
330 | 135 | <property name="visible">True</property> | ||
331 | 136 | <property name="can_focus">False</property> | ||
332 | 137 | <property name="xalign">0</property> | ||
333 | 138 | <property name="label" translatable="yes">Rock Out | ||
334 | 139 | <span foreground="#909090">Your library at your fingertips with Android, iPhone, and AirPlay | ||
335 | 140 | Plus the Ubuntu One Music store to grow your collection</span></property> | ||
336 | 141 | <property name="use_markup">True</property> | ||
337 | 142 | <property name="wrap">True</property> | ||
338 | 143 | </object> | ||
339 | 144 | <packing> | ||
340 | 145 | <property name="left_attach">1</property> | ||
341 | 146 | <property name="right_attach">2</property> | ||
342 | 147 | <property name="top_attach">2</property> | ||
343 | 148 | <property name="bottom_attach">3</property> | ||
344 | 149 | </packing> | ||
345 | 150 | </child> | ||
346 | 151 | <child> | ||
347 | 152 | <object class="GtkLabel" id="label6"> | ||
348 | 153 | <property name="visible">True</property> | ||
349 | 154 | <property name="can_focus">False</property> | ||
350 | 155 | <property name="xalign">0</property> | ||
351 | 156 | <property name="label" translatable="yes">Stay Productive | ||
352 | 157 | <span foreground="#909090">Keep your Firefox bookmarks and Tomboy notes synced</span></property> | ||
353 | 158 | <property name="use_markup">True</property> | ||
354 | 159 | <property name="wrap">True</property> | ||
355 | 160 | </object> | ||
356 | 161 | <packing> | ||
357 | 162 | <property name="left_attach">1</property> | ||
358 | 163 | <property name="right_attach">2</property> | ||
359 | 164 | <property name="top_attach">3</property> | ||
360 | 165 | <property name="bottom_attach">4</property> | ||
361 | 166 | </packing> | ||
362 | 167 | </child> | ||
363 | 168 | </object> | ||
364 | 169 | <packing> | ||
365 | 170 | <property name="expand">True</property> | ||
366 | 171 | <property name="fill">True</property> | ||
367 | 172 | <property name="position">0</property> | ||
368 | 173 | </packing> | ||
369 | 32 | </child> | 174 | </child> |
370 | 33 | </object> | ||
371 | 34 | <packing> | ||
372 | 35 | <property name="position">0</property> | ||
373 | 36 | </packing> | ||
374 | 37 | </child> | ||
375 | 38 | <child> | ||
376 | 39 | <object class="GtkAlignment" id="alignment2"> | ||
377 | 40 | <property name="visible">True</property> | ||
378 | 41 | <property name="xscale">0</property> | ||
379 | 42 | <property name="yscale">0</property> | ||
380 | 43 | <child> | 175 | <child> |
382 | 44 | <object class="GtkVBox" id="vbox2"> | 176 | <object class="GtkVBox" id="vbox1"> |
383 | 45 | <property name="visible">True</property> | 177 | <property name="visible">True</property> |
392 | 46 | <property name="spacing">10</property> | 178 | <property name="can_focus">False</property> |
393 | 47 | <child> | 179 | <child> |
394 | 48 | <object class="GtkButton" id="join_now_button"> | 180 | <object class="GtkLabel" id="warning_label"> |
395 | 49 | <property name="visible">True</property> | 181 | <property name="visible">True</property> |
396 | 50 | <property name="can_focus">True</property> | 182 | <property name="can_focus">False</property> |
397 | 51 | <property name="can_default">True</property> | 183 | <property name="label">A warning label that can be long. Possible really long, let's see how it behaves.</property> |
398 | 52 | <property name="receives_default">True</property> | 184 | <property name="wrap">True</property> |
399 | 53 | <signal name="clicked" handler="on_join_now_button_clicked"/> | 185 | </object> |
400 | 186 | <packing> | ||
401 | 187 | <property name="expand">False</property> | ||
402 | 188 | <property name="fill">True</property> | ||
403 | 189 | <property name="position">0</property> | ||
404 | 190 | </packing> | ||
405 | 191 | </child> | ||
406 | 192 | <child> | ||
407 | 193 | <object class="GtkAlignment" id="alignment2"> | ||
408 | 194 | <property name="visible">True</property> | ||
409 | 195 | <property name="can_focus">False</property> | ||
410 | 196 | <property name="xscale">0</property> | ||
411 | 197 | <property name="yscale">0</property> | ||
412 | 54 | <child> | 198 | <child> |
414 | 55 | <object class="GtkVBox" id="vbox1"> | 199 | <object class="GtkVBox" id="vbox2"> |
415 | 56 | <property name="visible">True</property> | 200 | <property name="visible">True</property> |
417 | 57 | <property name="spacing">5</property> | 201 | <property name="can_focus">False</property> |
418 | 202 | <property name="spacing">10</property> | ||
419 | 58 | <child> | 203 | <child> |
421 | 59 | <object class="GtkLabel" id="label1"> | 204 | <object class="GtkButton" id="join_now_button"> |
422 | 60 | <property name="visible">True</property> | 205 | <property name="visible">True</property> |
425 | 61 | <property name="label" translatable="yes"><span font_size="xx-large">Join now</span></property> | 206 | <property name="can_focus">True</property> |
426 | 62 | <property name="use_markup">True</property> | 207 | <property name="can_default">True</property> |
427 | 208 | <property name="receives_default">True</property> | ||
428 | 209 | <property name="use_action_appearance">False</property> | ||
429 | 210 | <signal name="clicked" handler="on_join_now_button_clicked" swapped="no"/> | ||
430 | 211 | <child> | ||
431 | 212 | <object class="GtkVBox" id="vbox3"> | ||
432 | 213 | <property name="visible">True</property> | ||
433 | 214 | <property name="can_focus">False</property> | ||
434 | 215 | <property name="spacing">5</property> | ||
435 | 216 | <child> | ||
436 | 217 | <object class="GtkLabel" id="label1"> | ||
437 | 218 | <property name="visible">True</property> | ||
438 | 219 | <property name="can_focus">False</property> | ||
439 | 220 | <property name="label" translatable="yes"><span font_size="xx-large">Join now</span></property> | ||
440 | 221 | <property name="use_markup">True</property> | ||
441 | 222 | </object> | ||
442 | 223 | <packing> | ||
443 | 224 | <property name="expand">True</property> | ||
444 | 225 | <property name="fill">True</property> | ||
445 | 226 | <property name="position">0</property> | ||
446 | 227 | </packing> | ||
447 | 228 | </child> | ||
448 | 229 | <child> | ||
449 | 230 | <object class="GtkLabel" id="label2"> | ||
450 | 231 | <property name="visible">True</property> | ||
451 | 232 | <property name="can_focus">False</property> | ||
452 | 233 | <property name="label" translatable="yes"><span foreground="#909090">2GB of free storage</span></property> | ||
453 | 234 | <property name="use_markup">True</property> | ||
454 | 235 | </object> | ||
455 | 236 | <packing> | ||
456 | 237 | <property name="expand">True</property> | ||
457 | 238 | <property name="fill">True</property> | ||
458 | 239 | <property name="position">1</property> | ||
459 | 240 | </packing> | ||
460 | 241 | </child> | ||
461 | 242 | </object> | ||
462 | 243 | </child> | ||
463 | 63 | </object> | 244 | </object> |
464 | 64 | <packing> | 245 | <packing> |
465 | 246 | <property name="expand">False</property> | ||
466 | 247 | <property name="fill">True</property> | ||
467 | 65 | <property name="position">0</property> | 248 | <property name="position">0</property> |
468 | 66 | </packing> | 249 | </packing> |
469 | 67 | </child> | 250 | </child> |
470 | 68 | <child> | 251 | <child> |
472 | 69 | <object class="GtkLabel" id="label2"> | 252 | <object class="GtkLinkButton" id="connect_button"> |
473 | 253 | <property name="label" translatable="yes">I already have an account!</property> | ||
474 | 70 | <property name="visible">True</property> | 254 | <property name="visible">True</property> |
477 | 71 | <property name="label" translatable="yes"><span foreground="grey">2GB of free storage</span></property> | 255 | <property name="can_focus">True</property> |
478 | 72 | <property name="use_markup">True</property> | 256 | <property name="receives_default">True</property> |
479 | 257 | <property name="use_action_appearance">False</property> | ||
480 | 258 | <property name="relief">none</property> | ||
481 | 259 | <signal name="clicked" handler="on_connect_button_clicked" swapped="no"/> | ||
482 | 73 | </object> | 260 | </object> |
483 | 74 | <packing> | 261 | <packing> |
484 | 262 | <property name="expand">False</property> | ||
485 | 263 | <property name="fill">False</property> | ||
486 | 75 | <property name="position">1</property> | 264 | <property name="position">1</property> |
487 | 76 | </packing> | 265 | </packing> |
488 | 77 | </child> | 266 | </child> |
489 | @@ -79,50 +268,28 @@ | |||
490 | 79 | </child> | 268 | </child> |
491 | 80 | </object> | 269 | </object> |
492 | 81 | <packing> | 270 | <packing> |
509 | 82 | <property name="expand">False</property> | 271 | <property name="expand">True</property> |
510 | 83 | <property name="position">0</property> | 272 | <property name="fill">True</property> |
495 | 84 | </packing> | ||
496 | 85 | </child> | ||
497 | 86 | <child> | ||
498 | 87 | <object class="GtkLinkButton" id="connect_button"> | ||
499 | 88 | <property name="label" translatable="yes">I already have an account!</property> | ||
500 | 89 | <property name="visible">True</property> | ||
501 | 90 | <property name="can_focus">True</property> | ||
502 | 91 | <property name="receives_default">True</property> | ||
503 | 92 | <property name="relief">none</property> | ||
504 | 93 | <signal name="clicked" handler="on_connect_button_clicked"/> | ||
505 | 94 | </object> | ||
506 | 95 | <packing> | ||
507 | 96 | <property name="expand">False</property> | ||
508 | 97 | <property name="fill">False</property> | ||
511 | 98 | <property name="position">1</property> | 273 | <property name="position">1</property> |
512 | 99 | </packing> | 274 | </packing> |
513 | 100 | </child> | 275 | </child> |
514 | 101 | </object> | 276 | </object> |
515 | 277 | <packing> | ||
516 | 278 | <property name="expand">False</property> | ||
517 | 279 | <property name="fill">True</property> | ||
518 | 280 | <property name="position">1</property> | ||
519 | 281 | </packing> | ||
520 | 102 | </child> | 282 | </child> |
521 | 103 | </object> | 283 | </object> |
522 | 104 | <packing> | ||
523 | 105 | <property name="expand">False</property> | ||
524 | 106 | <property name="position">1</property> | ||
525 | 107 | </packing> | ||
526 | 108 | </child> | 284 | </child> |
527 | 109 | </object> | 285 | </object> |
528 | 110 | </child> | 286 | </child> |
529 | 111 | </object> | 287 | </object> |
530 | 112 | <packing> | 288 | <packing> |
531 | 289 | <property name="expand">True</property> | ||
532 | 290 | <property name="fill">True</property> | ||
533 | 113 | <property name="position">1</property> | 291 | <property name="position">1</property> |
534 | 114 | </packing> | 292 | </packing> |
535 | 115 | </child> | 293 | </child> |
536 | 116 | <child> | ||
537 | 117 | <object class="GtkLabel" id="warning_label"> | ||
538 | 118 | <property name="visible">True</property> | ||
539 | 119 | <property name="wrap">True</property> | ||
540 | 120 | <property name="ellipsize">end</property> | ||
541 | 121 | </object> | ||
542 | 122 | <packing> | ||
543 | 123 | <property name="expand">False</property> | ||
544 | 124 | <property name="position">2</property> | ||
545 | 125 | </packing> | ||
546 | 126 | </child> | ||
547 | 127 | </object> | 294 | </object> |
548 | 128 | </interface> | 295 | </interface> |
549 | 129 | 296 | ||
550 | === modified file 'data/volumes.ui' | |||
551 | --- data/volumes.ui 2011-01-25 19:08:59 +0000 | |||
552 | +++ data/volumes.ui 2011-02-12 03:22:55 +0000 | |||
553 | @@ -2,6 +2,26 @@ | |||
554 | 2 | <interface> | 2 | <interface> |
555 | 3 | <requires lib="gtk+" version="2.22"/> | 3 | <requires lib="gtk+" version="2.22"/> |
556 | 4 | <!-- interface-naming-policy project-wide --> | 4 | <!-- interface-naming-policy project-wide --> |
557 | 5 | <object class="GtkTreeStore" id="volumes_store"> | ||
558 | 6 | <columns> | ||
559 | 7 | <!-- column-name description --> | ||
560 | 8 | <column type="gchararray"/> | ||
561 | 9 | <!-- column-name subscribed --> | ||
562 | 10 | <column type="gboolean"/> | ||
563 | 11 | <!-- column-name icon-name --> | ||
564 | 12 | <column type="gchararray"/> | ||
565 | 13 | <!-- column-name subscribed-visible --> | ||
566 | 14 | <column type="gboolean"/> | ||
567 | 15 | <!-- column-name subscribed-sensitive --> | ||
568 | 16 | <column type="gboolean"/> | ||
569 | 17 | <!-- column-name icon-size --> | ||
570 | 18 | <column type="gint"/> | ||
571 | 19 | <!-- column-name identifier --> | ||
572 | 20 | <column type="gchararray"/> | ||
573 | 21 | <!-- column-name path --> | ||
574 | 22 | <column type="gchararray"/> | ||
575 | 23 | </columns> | ||
576 | 24 | </object> | ||
577 | 5 | <object class="GtkAlignment" id="itself"> | 25 | <object class="GtkAlignment" id="itself"> |
578 | 6 | <property name="visible">True</property> | 26 | <property name="visible">True</property> |
579 | 7 | <property name="can_focus">False</property> | 27 | <property name="can_focus">False</property> |
580 | @@ -18,6 +38,7 @@ | |||
581 | 18 | <property name="model">volumes_store</property> | 38 | <property name="model">volumes_store</property> |
582 | 19 | <property name="rules_hint">True</property> | 39 | <property name="rules_hint">True</property> |
583 | 20 | <property name="tooltip_column">0</property> | 40 | <property name="tooltip_column">0</property> |
584 | 41 | <signal name="row-activated" handler="on_volumes_view_row_activated" swapped="no"/> | ||
585 | 21 | <child> | 42 | <child> |
586 | 22 | <object class="GtkTreeViewColumn" id="treeviewcolumn2"> | 43 | <object class="GtkTreeViewColumn" id="treeviewcolumn2"> |
587 | 23 | <property name="resizable">True</property> | 44 | <property name="resizable">True</property> |
588 | @@ -46,7 +67,7 @@ | |||
589 | 46 | <child> | 67 | <child> |
590 | 47 | <object class="GtkTreeViewColumn" id="treeviewcolumn3"> | 68 | <object class="GtkTreeViewColumn" id="treeviewcolumn3"> |
591 | 48 | <property name="sizing">autosize</property> | 69 | <property name="sizing">autosize</property> |
593 | 49 | <property name="title">On this device?</property> | 70 | <property name="title" translatable="yes">Sync locally?</property> |
594 | 50 | <child> | 71 | <child> |
595 | 51 | <object class="GtkCellRendererToggle" id="cellrenderertoggle1"> | 72 | <object class="GtkCellRendererToggle" id="cellrenderertoggle1"> |
596 | 52 | <property name="indicator_size">15</property> | 73 | <property name="indicator_size">15</property> |
597 | @@ -73,22 +94,4 @@ | |||
598 | 73 | </object> | 94 | </object> |
599 | 74 | </child> | 95 | </child> |
600 | 75 | </object> | 96 | </object> |
601 | 76 | <object class="GtkTreeStore" id="volumes_store"> | ||
602 | 77 | <columns> | ||
603 | 78 | <!-- column-name description --> | ||
604 | 79 | <column type="gchararray"/> | ||
605 | 80 | <!-- column-name subscribed --> | ||
606 | 81 | <column type="gboolean"/> | ||
607 | 82 | <!-- column-name icon-name --> | ||
608 | 83 | <column type="gchararray"/> | ||
609 | 84 | <!-- column-name subscribed-visible --> | ||
610 | 85 | <column type="gboolean"/> | ||
611 | 86 | <!-- column-name subscribed-sensitive --> | ||
612 | 87 | <column type="gboolean"/> | ||
613 | 88 | <!-- column-name icon-size --> | ||
614 | 89 | <column type="gint"/> | ||
615 | 90 | <!-- column-name identifier --> | ||
616 | 91 | <column type="gchararray"/> | ||
617 | 92 | </columns> | ||
618 | 93 | </object> | ||
619 | 94 | </interface> | 97 | </interface> |
620 | 95 | 98 | ||
621 | === modified file 'debian/changelog' | |||
622 | --- debian/changelog 2011-02-07 07:55:07 +0000 | |||
623 | +++ debian/changelog 2011-02-12 03:22:55 +0000 | |||
624 | @@ -1,3 +1,20 @@ | |||
625 | 1 | ubuntuone-control-panel (0.8.3-0ubuntu1) natty; urgency=low | ||
626 | 2 | |||
627 | 3 | * New upstream release. | ||
628 | 4 | - Support share subscription in Folders tab (LP: #714583) | ||
629 | 5 | - Use more concise text on overview page (LP: #715732) | ||
630 | 6 | - Set widget names to style properly (LP: #716678) | ||
631 | 7 | - Place usage bar label on top (LP: #715713) | ||
632 | 8 | - Inconsistent placement of 'remove' button (LP: #715804) | ||
633 | 9 | - Message text should say 'your personal cloud' (LP: #715858) | ||
634 | 10 | - Shares to me path looks awful (LP: #716431) | ||
635 | 11 | - Clicking a folder should open it (LP: #716499) | ||
636 | 12 | - Subtext in 'join now' button is hard to read (LP: #716504) | ||
637 | 13 | - "On this device?" string is inconsistent with its action (LP: #717159) | ||
638 | 14 | - Devices don't necessarily have a sync service (LP: #717230) | ||
639 | 15 | |||
640 | 16 | -- Rodney Dawes <rodney.dawes@ubuntu.com> Fri, 11 Feb 2011 22:07:23 -0500 | ||
641 | 17 | |||
642 | 1 | ubuntuone-control-panel (0.8.2-0ubuntu1) natty; urgency=low | 18 | ubuntuone-control-panel (0.8.2-0ubuntu1) natty; urgency=low |
643 | 2 | 19 | ||
644 | 3 | * New upstream release: | 20 | * New upstream release: |
645 | 4 | 21 | ||
646 | === modified file 'debian/python-ubuntuone-control-panel.install' | |||
647 | --- debian/python-ubuntuone-control-panel.install 2010-12-06 12:27:11 +0000 | |||
648 | +++ debian/python-ubuntuone-control-panel.install 2011-02-12 03:22:55 +0000 | |||
649 | @@ -1,1 +1,4 @@ | |||
651 | 1 | debian/tmp/usr/lib/python2.*/*-packages/ubuntuone/controlpanel/*.py | 1 | debian/tmp/usr/lib/python2.*/*-packages/*.pth |
652 | 2 | debian/tmp/usr/lib/python2.*/*-packages/*/ubuntuone/__init__.py | ||
653 | 3 | debian/tmp/usr/lib/python2.*/*-packages/*/ubuntuone/controlpanel/*.py | ||
654 | 4 | |||
655 | 2 | 5 | ||
656 | === modified file 'debian/ubuntuone-control-panel-gtk.install' | |||
657 | --- debian/ubuntuone-control-panel-gtk.install 2011-01-27 22:13:48 +0000 | |||
658 | +++ debian/ubuntuone-control-panel-gtk.install 2011-02-12 03:22:55 +0000 | |||
659 | @@ -4,4 +4,5 @@ | |||
660 | 4 | debian/tmp/usr/share/ubuntuone-control-panel/*.ui | 4 | debian/tmp/usr/share/ubuntuone-control-panel/*.ui |
661 | 5 | debian/tmp/usr/share/ubuntuone-control-panel/*.png | 5 | debian/tmp/usr/share/ubuntuone-control-panel/*.png |
662 | 6 | debian/tmp/usr/share/man/man1/ubuntuone-control-panel-gtk.* | 6 | debian/tmp/usr/share/man/man1/ubuntuone-control-panel-gtk.* |
664 | 7 | debian/tmp/usr/lib/python2.*/*-packages/ubuntuone/controlpanel/gtk/*.py | 7 | debian/tmp/usr/lib/python2.*/*-packages/*/ubuntuone/controlpanel/gtk |
665 | 8 | |||
666 | 8 | 9 | ||
667 | === modified file 'setup.py' | |||
668 | --- setup.py 2011-02-04 20:02:28 +0000 | |||
669 | +++ setup.py 2011-02-12 03:22:55 +0000 | |||
670 | @@ -76,7 +76,7 @@ | |||
671 | 76 | 76 | ||
672 | 77 | DistUtilsExtra.auto.setup( | 77 | DistUtilsExtra.auto.setup( |
673 | 78 | name='ubuntuone-control-panel', | 78 | name='ubuntuone-control-panel', |
675 | 79 | version='0.8.2', | 79 | version='0.8.3', |
676 | 80 | license='GPL v3', | 80 | license='GPL v3', |
677 | 81 | author='Natalia Bidart', | 81 | author='Natalia Bidart', |
678 | 82 | author_email='natalia.bidart@canonical.com', | 82 | author_email='natalia.bidart@canonical.com', |
679 | @@ -85,6 +85,7 @@ | |||
680 | 85 | 'DBus service to query/modify all the Ubuntu One bits.', | 85 | 'DBus service to query/modify all the Ubuntu One bits.', |
681 | 86 | url='https://launchpad.net/ubuntuone-control-panel', | 86 | url='https://launchpad.net/ubuntuone-control-panel', |
682 | 87 | packages=['ubuntuone.controlpanel', 'ubuntuone.controlpanel.gtk'], | 87 | packages=['ubuntuone.controlpanel', 'ubuntuone.controlpanel.gtk'], |
683 | 88 | extra_path='ubuntuone-control-panel', | ||
684 | 88 | data_files=[ | 89 | data_files=[ |
685 | 89 | ('lib/ubuntuone-control-panel', | 90 | ('lib/ubuntuone-control-panel', |
686 | 90 | ['bin/ubuntuone-control-panel-backend']), | 91 | ['bin/ubuntuone-control-panel-backend']), |
687 | 91 | 92 | ||
688 | === modified file 'ubuntuone-control-panel-gtk.desktop.in' | |||
689 | --- ubuntuone-control-panel-gtk.desktop.in 2011-01-07 20:07:39 +0000 | |||
690 | +++ ubuntuone-control-panel-gtk.desktop.in 2011-02-12 03:22:55 +0000 | |||
691 | @@ -8,6 +8,7 @@ | |||
692 | 8 | StartupNotify=true | 8 | StartupNotify=true |
693 | 9 | Categories=GNOME;GTK;Settings; | 9 | Categories=GNOME;GTK;Settings; |
694 | 10 | X-Ayatana-Desktop-Shortcuts=U1 | 10 | X-Ayatana-Desktop-Shortcuts=U1 |
695 | 11 | X-Ayatana-Appmenu-Show-Stubs=False | ||
696 | 11 | 12 | ||
697 | 12 | [U1 Shortcut Group] | 13 | [U1 Shortcut Group] |
698 | 13 | Name=Ubuntu One | 14 | Name=Ubuntu One |
699 | 14 | 15 | ||
700 | === added file 'ubuntuone.controlpanel.pth' | |||
701 | --- ubuntuone.controlpanel.pth 1970-01-01 00:00:00 +0000 | |||
702 | +++ ubuntuone.controlpanel.pth 2011-02-12 03:22:55 +0000 | |||
703 | @@ -0,0 +1,2 @@ | |||
704 | 1 | ubuntuone-control-panel | ||
705 | 2 | |||
706 | 0 | 3 | ||
707 | === modified file 'ubuntuone/controlpanel/backend.py' | |||
708 | --- ubuntuone/controlpanel/backend.py 2011-01-25 19:08:59 +0000 | |||
709 | +++ ubuntuone/controlpanel/backend.py 2011-02-12 03:22:55 +0000 | |||
710 | @@ -19,6 +19,8 @@ | |||
711 | 19 | 19 | ||
712 | 20 | """A backend for the Ubuntu One Control Panel.""" | 20 | """A backend for the Ubuntu One Control Panel.""" |
713 | 21 | 21 | ||
714 | 22 | from collections import defaultdict | ||
715 | 23 | |||
716 | 22 | from twisted.internet.defer import inlineCallbacks, returnValue | 24 | from twisted.internet.defer import inlineCallbacks, returnValue |
717 | 23 | 25 | ||
718 | 24 | from ubuntuone.controlpanel import dbus_client | 26 | from ubuntuone.controlpanel import dbus_client |
719 | @@ -62,12 +64,19 @@ | |||
720 | 62 | class ControlBackend(object): | 64 | class ControlBackend(object): |
721 | 63 | """The control panel backend.""" | 65 | """The control panel backend.""" |
722 | 64 | 66 | ||
723 | 67 | ROOT_TYPE = u'ROOT' | ||
724 | 68 | FOLDER_TYPE = u'UDF' | ||
725 | 69 | SHARE_TYPE = u'SHARE' | ||
726 | 70 | NAME_NOT_SET = u'ENAMENOTSET' | ||
727 | 71 | |||
728 | 65 | def __init__(self): | 72 | def __init__(self): |
729 | 66 | """Initialize the webclient.""" | 73 | """Initialize the webclient.""" |
730 | 67 | self.wc = WebClient(dbus_client.get_credentials) | 74 | self.wc = WebClient(dbus_client.get_credentials) |
731 | 68 | self._status_changed_handler = None | 75 | self._status_changed_handler = None |
732 | 69 | self.status_changed_handler = lambda *a: None | 76 | self.status_changed_handler = lambda *a: None |
733 | 70 | 77 | ||
734 | 78 | self._volumes = {} # cache last known volume info | ||
735 | 79 | |||
736 | 71 | def _process_file_sync_status(self, status): | 80 | def _process_file_sync_status(self, status): |
737 | 72 | """Process raw file sync status into custom format. | 81 | """Process raw file sync status into custom format. |
738 | 73 | 82 | ||
739 | @@ -328,17 +337,54 @@ | |||
740 | 328 | @inlineCallbacks | 337 | @inlineCallbacks |
741 | 329 | def volumes_info(self): | 338 | def volumes_info(self): |
742 | 330 | """Get the volumes info.""" | 339 | """Get the volumes info.""" |
743 | 340 | self._volumes = {} | ||
744 | 341 | |||
745 | 331 | account = yield self.account_info() | 342 | account = yield self.account_info() |
746 | 332 | root_dir = yield dbus_client.get_root_dir() | 343 | root_dir = yield dbus_client.get_root_dir() |
747 | 344 | shares_dir = yield dbus_client.get_shares_dir() | ||
748 | 345 | shares_dir_link = yield dbus_client.get_shares_dir_link() | ||
749 | 333 | folders = yield dbus_client.get_folders() | 346 | folders = yield dbus_client.get_folders() |
750 | 347 | shares = yield dbus_client.get_shares() | ||
751 | 334 | 348 | ||
752 | 335 | free_bytes = int(account['quota_total']) - int(account['quota_used']) | 349 | free_bytes = int(account['quota_total']) - int(account['quota_used']) |
753 | 336 | root_volume = {u'volume_id': u'', u'path': root_dir, | 350 | root_volume = {u'volume_id': u'', u'path': root_dir, |
755 | 337 | u'subscribed': 'True', u'type': u'ROOT'} | 351 | u'subscribed': 'True', u'type': self.ROOT_TYPE} |
756 | 352 | self._volumes[u''] = root_volume | ||
757 | 353 | |||
758 | 354 | # group shares by the offering user | ||
759 | 355 | shares_result = defaultdict(list) | ||
760 | 356 | for share in shares: | ||
761 | 357 | share[u'type'] = self.SHARE_TYPE | ||
762 | 358 | |||
763 | 359 | vid = share['volume_id'] | ||
764 | 360 | assert vid not in self._volumes | ||
765 | 361 | self._volumes[vid] = share | ||
766 | 362 | |||
767 | 363 | if not bool(share['accepted']): | ||
768 | 364 | continue | ||
769 | 365 | |||
770 | 366 | nicer_path = share[u'path'].replace(shares_dir, shares_dir_link) | ||
771 | 367 | share[u'path'] = nicer_path | ||
772 | 368 | |||
773 | 369 | username = share['other_visible_name'] | ||
774 | 370 | if not username: | ||
775 | 371 | username = u'%s (%s)' % (share['other_username'], | ||
776 | 372 | self.NAME_NOT_SET) | ||
777 | 373 | |||
778 | 374 | shares_result[username].append(share) | ||
779 | 375 | |||
780 | 376 | for folder in folders: | ||
781 | 377 | folder[u'type'] = self.FOLDER_TYPE | ||
782 | 378 | |||
783 | 379 | vid = folder['volume_id'] | ||
784 | 380 | assert vid not in self._volumes | ||
785 | 381 | self._volumes[vid] = folder | ||
786 | 338 | 382 | ||
787 | 339 | result = [(u'', unicode(free_bytes), [root_volume] + folders)] | 383 | result = [(u'', unicode(free_bytes), [root_volume] + folders)] |
788 | 340 | 384 | ||
790 | 341 | # later, we may request shares info as well | 385 | for other_username, shares in shares_result.iteritems(): |
791 | 386 | result.append((other_username, shares[0][u'free_bytes'], shares)) | ||
792 | 387 | |||
793 | 342 | returnValue(result) | 388 | returnValue(result) |
794 | 343 | 389 | ||
795 | 344 | @log_call(logger.debug) | 390 | @log_call(logger.debug) |
796 | @@ -359,16 +405,18 @@ | |||
797 | 359 | @inlineCallbacks | 405 | @inlineCallbacks |
798 | 360 | def subscribe_volume(self, volume_id): | 406 | def subscribe_volume(self, volume_id): |
799 | 361 | """Subscribe to 'volume_id'.""" | 407 | """Subscribe to 'volume_id'.""" |
803 | 362 | # when dealing with shares, we need to check if 'volume_id' | 408 | if self._volumes[volume_id][u'type'] == self.FOLDER_TYPE: |
804 | 363 | # is a folder or a share | 409 | yield dbus_client.subscribe_folder(volume_id) |
805 | 364 | yield dbus_client.subscribe_folder(volume_id) | 410 | elif self._volumes[volume_id][u'type'] == self.SHARE_TYPE: |
806 | 411 | yield dbus_client.subscribe_share(volume_id) | ||
807 | 365 | 412 | ||
808 | 366 | @inlineCallbacks | 413 | @inlineCallbacks |
809 | 367 | def unsubscribe_volume(self, volume_id): | 414 | def unsubscribe_volume(self, volume_id): |
810 | 368 | """Unsubscribe from 'volume_id'.""" | 415 | """Unsubscribe from 'volume_id'.""" |
814 | 369 | # when dealing with shares, we need to check if 'volume_id' | 416 | if self._volumes[volume_id][u'type'] == self.FOLDER_TYPE: |
815 | 370 | # is a folder or a share | 417 | yield dbus_client.unsubscribe_folder(volume_id) |
816 | 371 | yield dbus_client.unsubscribe_folder(volume_id) | 418 | elif self._volumes[volume_id][u'type'] == self.SHARE_TYPE: |
817 | 419 | yield dbus_client.unsubscribe_share(volume_id) | ||
818 | 372 | 420 | ||
819 | 373 | @log_call(logger.debug) | 421 | @log_call(logger.debug) |
820 | 374 | @inlineCallbacks | 422 | @inlineCallbacks |
821 | 375 | 423 | ||
822 | === modified file 'ubuntuone/controlpanel/dbus_client.py' | |||
823 | --- ubuntuone/controlpanel/dbus_client.py 2011-01-25 19:08:59 +0000 | |||
824 | +++ ubuntuone/controlpanel/dbus_client.py 2011-02-12 03:22:55 +0000 | |||
825 | @@ -221,6 +221,22 @@ | |||
826 | 221 | return d | 221 | return d |
827 | 222 | 222 | ||
828 | 223 | 223 | ||
829 | 224 | def get_shares_dir(): | ||
830 | 225 | """Retrieve the shares information from syncdaemon.""" | ||
831 | 226 | d = defer.Deferred() | ||
832 | 227 | proxy = get_syncdaemon_proxy("/", sd_dbus_iface.DBUS_IFACE_SYNC_NAME) | ||
833 | 228 | proxy.get_sharesdir(reply_handler=d.callback, error_handler=d.errback) | ||
834 | 229 | return d | ||
835 | 230 | |||
836 | 231 | |||
837 | 232 | def get_shares_dir_link(): | ||
838 | 233 | """Retrieve the shares information from syncdaemon.""" | ||
839 | 234 | d = defer.Deferred() | ||
840 | 235 | proxy = get_syncdaemon_proxy("/", sd_dbus_iface.DBUS_IFACE_SYNC_NAME) | ||
841 | 236 | proxy.get_sharesdir_link(reply_handler=d.callback, error_handler=d.errback) | ||
842 | 237 | return d | ||
843 | 238 | |||
844 | 239 | |||
845 | 224 | def get_folders(): | 240 | def get_folders(): |
846 | 225 | """Retrieve the folders information from syncdaemon.""" | 241 | """Retrieve the folders information from syncdaemon.""" |
847 | 226 | d = defer.Deferred() | 242 | d = defer.Deferred() |
848 | @@ -256,7 +272,7 @@ | |||
849 | 256 | proxy = get_folders_syncdaemon_proxy() | 272 | proxy = get_folders_syncdaemon_proxy() |
850 | 257 | 273 | ||
851 | 258 | sig = proxy.connect_to_signal('FolderSubscribed', d.callback) | 274 | sig = proxy.connect_to_signal('FolderSubscribed', d.callback) |
853 | 259 | cb = lambda folder_info, error: d.errback(VolumesError(folder_info, error)) | 275 | cb = lambda info, error: d.errback(VolumesError(info['id'], error)) |
854 | 260 | esig = proxy.connect_to_signal('FolderSubscribeError', cb) | 276 | esig = proxy.connect_to_signal('FolderSubscribeError', cb) |
855 | 261 | 277 | ||
856 | 262 | proxy.subscribe(folder_id, reply_handler=no_op, error_handler=no_op) | 278 | proxy.subscribe(folder_id, reply_handler=no_op, error_handler=no_op) |
857 | @@ -277,7 +293,7 @@ | |||
858 | 277 | proxy = get_folders_syncdaemon_proxy() | 293 | proxy = get_folders_syncdaemon_proxy() |
859 | 278 | 294 | ||
860 | 279 | sig = proxy.connect_to_signal('FolderUnSubscribed', d.callback) | 295 | sig = proxy.connect_to_signal('FolderUnSubscribed', d.callback) |
862 | 280 | cb = lambda folder_info, error: d.errback(VolumesError(folder_info, error)) | 296 | cb = lambda info, error: d.errback(VolumesError(info['id'], error)) |
863 | 281 | esig = proxy.connect_to_signal('FolderUnSubscribeError', cb) | 297 | esig = proxy.connect_to_signal('FolderUnSubscribeError', cb) |
864 | 282 | 298 | ||
865 | 283 | proxy.unsubscribe(folder_id, reply_handler=no_op, error_handler=no_op) | 299 | proxy.unsubscribe(folder_id, reply_handler=no_op, error_handler=no_op) |
866 | @@ -292,6 +308,31 @@ | |||
867 | 292 | return d | 308 | return d |
868 | 293 | 309 | ||
869 | 294 | 310 | ||
870 | 311 | @defer.inlineCallbacks | ||
871 | 312 | def get_shares(): | ||
872 | 313 | """Retrieve the shares information from syncdaemon.""" | ||
873 | 314 | result = yield SyncDaemonTool(bus=dbus.SessionBus()).get_shares() | ||
874 | 315 | defer.returnValue(result) | ||
875 | 316 | |||
876 | 317 | |||
877 | 318 | @defer.inlineCallbacks | ||
878 | 319 | def subscribe_share(share_id): | ||
879 | 320 | """Subscribe to 'share_id'.""" | ||
880 | 321 | try: | ||
881 | 322 | yield SyncDaemonTool(bus=dbus.SessionBus()).subscribe_share(share_id) | ||
882 | 323 | except Exception, e: | ||
883 | 324 | raise VolumesError(share_id, e) | ||
884 | 325 | |||
885 | 326 | |||
886 | 327 | @defer.inlineCallbacks | ||
887 | 328 | def unsubscribe_share(share_id): | ||
888 | 329 | """Unsubscribe 'share_id'.""" | ||
889 | 330 | try: | ||
890 | 331 | yield SyncDaemonTool(bus=dbus.SessionBus()).unsubscribe_share(share_id) | ||
891 | 332 | except Exception, e: | ||
892 | 333 | raise VolumesError(share_id, e) | ||
893 | 334 | |||
894 | 335 | |||
895 | 295 | def get_current_status(): | 336 | def get_current_status(): |
896 | 296 | """Retrieve the current status from syncdaemon.""" | 337 | """Retrieve the current status from syncdaemon.""" |
897 | 297 | d = defer.Deferred() | 338 | d = defer.Deferred() |
898 | 298 | 339 | ||
899 | === modified file 'ubuntuone/controlpanel/gtk/gui.py' | |||
900 | --- ubuntuone/controlpanel/gtk/gui.py 2011-02-04 20:02:28 +0000 | |||
901 | +++ ubuntuone/controlpanel/gtk/gui.py 2011-02-12 03:22:55 +0000 | |||
902 | @@ -61,24 +61,13 @@ | |||
903 | 61 | 61 | ||
904 | 62 | # To be replaced by values from the theme or Ubuntu One' specific (LP: #673663) | 62 | # To be replaced by values from the theme or Ubuntu One' specific (LP: #673663) |
905 | 63 | ORANGE = '#c95724' | 63 | ORANGE = '#c95724' |
906 | 64 | ERROR_COLOR = 'red' | ||
907 | 64 | LOADING = _('Loading...') | 65 | LOADING = _('Loading...') |
908 | 65 | OVERVIEW_MSGS = [ | ||
909 | 66 | _('Backup and access your files from <b>any</b> computer (Ubuntu & ' | ||
910 | 67 | 'Windows), mobile device (Android) or the web.'), | ||
911 | 68 | _('A <b>portable address book</b> that unifies your most important ' | ||
912 | 69 | 'contact sources: mobile phones, social networks, email clients and ' | ||
913 | 70 | 'services.'), | ||
914 | 71 | _('A <b>personal music library</b> that can be streamed to Android, ' | ||
915 | 72 | 'iPhone and AirPlay-enabled devices.'), | ||
916 | 73 | _('Add to that music library with a <b>Music Store</b> that automatically ' | ||
917 | 74 | 'delivers to your personal cloud and connected devices.'), | ||
918 | 75 | _('Keep your <b>Firefox bookmarks</b> and <b>Tomboy notes</b> in sync ' | ||
919 | 76 | 'across computers (Ubuntu & Windows).'), | ||
920 | 77 | ] | ||
921 | 78 | VALUE_ERROR = _('Value could not be retrieved.') | 66 | VALUE_ERROR = _('Value could not be retrieved.') |
923 | 79 | WARNING_MARKUP = '<span foreground="%s"><b>%%s</b></span>' % ORANGE | 67 | WARNING_MARKUP = '<span foreground="%s"><b>%%s</b></span>' % ERROR_COLOR |
924 | 80 | KILOBYTES = 1024 | 68 | KILOBYTES = 1024 |
925 | 81 | NO_OP = lambda *a, **kw: None | 69 | NO_OP = lambda *a, **kw: None |
926 | 70 | FILE_URI_PREFIX = 'file://' | ||
927 | 82 | 71 | ||
928 | 83 | 72 | ||
929 | 84 | def error_handler(*args, **kwargs): | 73 | def error_handler(*args, **kwargs): |
930 | @@ -109,7 +98,7 @@ | |||
931 | 109 | @log_call(logger.debug) | 98 | @log_call(logger.debug) |
932 | 110 | def uri_hook(button, uri, *args, **kwargs): | 99 | def uri_hook(button, uri, *args, **kwargs): |
933 | 111 | """Open an URI or do nothing if URI is not an URL.""" | 100 | """Open an URI or do nothing if URI is not an URL.""" |
935 | 112 | if uri.startswith('http'): | 101 | if uri.startswith('http') or uri.startswith(FILE_URI_PREFIX): |
936 | 113 | gtk.show_uri(None, uri, gtk.gdk.CURRENT_TIME) | 102 | gtk.show_uri(None, uri, gtk.gdk.CURRENT_TIME) |
937 | 114 | 103 | ||
938 | 115 | 104 | ||
939 | @@ -222,30 +211,27 @@ | |||
940 | 222 | 211 | ||
941 | 223 | CREDENTIALS_ERROR = _('There was a problem while retrieving the ' | 212 | CREDENTIALS_ERROR = _('There was a problem while retrieving the ' |
942 | 224 | 'credentials.') | 213 | 'credentials.') |
945 | 225 | AUTHORIZATION_DENIED = _('The authentication was cancelled. Please either ' | 214 | AUTHORIZATION_DENIED = _('The authentication was cancelled.') |
944 | 226 | 'click join or connect to continue.') | ||
946 | 227 | NETWORK_OFFLINE = _('An internet connection is required to join or sign ' | 215 | NETWORK_OFFLINE = _('An internet connection is required to join or sign ' |
947 | 228 | 'in to %(app_name)s.') | 216 | 'in to %(app_name)s.') |
948 | 229 | NETWORK_UNKNOWN = _('The internet connection state couldn\'t be ' | 217 | NETWORK_UNKNOWN = _('The internet connection state couldn\'t be ' |
949 | 230 | 'discovered. Maybe NetworkManager is not running?') | 218 | 'discovered. Maybe NetworkManager is not running?') |
950 | 231 | 219 | ||
951 | 232 | CONNECT = _('Connect to Ubuntu One') | 220 | CONNECT = _('Connect to Ubuntu One') |
952 | 233 | BULLET = '<span foreground="%s">✔</span>' % ORANGE | ||
953 | 234 | 221 | ||
955 | 235 | def __init__(self, main_window, messages=None): | 222 | def __init__(self, main_window): |
956 | 236 | GreyableBin.__init__(self) | 223 | GreyableBin.__init__(self) |
957 | 237 | ControlPanelMixin.__init__(self, filename='overview.ui') | 224 | ControlPanelMixin.__init__(self, filename='overview.ui') |
958 | 238 | self.add(self.itself) | 225 | self.add(self.itself) |
959 | 239 | self.warning_label.set_text('') | 226 | self.warning_label.set_text('') |
960 | 240 | self.warning_label.set_property('xalign', 0.5) | 227 | self.warning_label.set_property('xalign', 0.5) |
962 | 241 | self.connect('size-allocate', on_size_allocate, self.warning_label) | 228 | |
963 | 229 | self.header.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(DEFAULT_BG)) | ||
964 | 242 | 230 | ||
965 | 243 | self.connect_button.set_uri(self.CONNECT) | 231 | self.connect_button.set_uri(self.CONNECT) |
966 | 244 | 232 | ||
967 | 245 | self.main_window = main_window | 233 | self.main_window = main_window |
968 | 246 | self._credentials_are_new = False | 234 | self._credentials_are_new = False |
969 | 247 | self._messages = messages | ||
970 | 248 | self._build_messages() | ||
971 | 249 | self.show() | 235 | self.show() |
972 | 250 | 236 | ||
973 | 251 | bus = dbus.SessionBus() | 237 | bus = dbus.SessionBus() |
974 | @@ -274,21 +260,6 @@ | |||
975 | 274 | self.network_manager_state = networkstate.NetworkManagerState(**kw) | 260 | self.network_manager_state = networkstate.NetworkManagerState(**kw) |
976 | 275 | self.network_manager_state.find_online_state() | 261 | self.network_manager_state.find_online_state() |
977 | 276 | 262 | ||
978 | 277 | def _build_messages(self): | ||
979 | 278 | """List messages in a itemized list.""" | ||
980 | 279 | if self._messages is None: | ||
981 | 280 | self._messages = OVERVIEW_MSGS | ||
982 | 281 | |||
983 | 282 | for msg in self._messages: | ||
984 | 283 | label = gtk.Label() | ||
985 | 284 | label.set_markup(self.BULLET + ' ' + msg) | ||
986 | 285 | label.set_property('xalign', 0) | ||
987 | 286 | label.set_property('wrap', True) | ||
988 | 287 | self.messages.connect('size-allocate', on_size_allocate, label) | ||
989 | 288 | |||
990 | 289 | self.messages.pack_start(label) | ||
991 | 290 | self.messages.show_all() | ||
992 | 291 | |||
993 | 292 | def _set_warning(self, message, label=None): | 263 | def _set_warning(self, message, label=None): |
994 | 293 | """Set 'message' as global warning.""" | 264 | """Set 'message' as global warning.""" |
995 | 294 | ControlPanelMixin._set_warning(self, message, | 265 | ControlPanelMixin._set_warning(self, message, |
996 | @@ -419,18 +390,22 @@ | |||
997 | 419 | class VolumesPanel(UbuntuOneBin, ControlPanelMixin): | 390 | class VolumesPanel(UbuntuOneBin, ControlPanelMixin): |
998 | 420 | """The volumes panel.""" | 391 | """The volumes panel.""" |
999 | 421 | 392 | ||
1002 | 422 | TITLE = _('Select the folders from your cloud that you want synchronized ' | 393 | TITLE = _('Select the folders from your personal cloud that you want ' |
1003 | 423 | 'in this device.') | 394 | 'synchronized in this device.') |
1004 | 424 | MY_FOLDERS = _('My folders') | 395 | MY_FOLDERS = _('My folders') |
1005 | 425 | ALWAYS_SUBSCRIBED = _('Always in sync!') | 396 | ALWAYS_SUBSCRIBED = _('Always in sync!') |
1006 | 426 | FREE_SPACE = _('%(free_space)s available storage') | 397 | FREE_SPACE = _('%(free_space)s available storage') |
1007 | 398 | NO_VOLUMES = _('No folders to show.') | ||
1008 | 399 | NAME_NOT_SET = _('[unknown user name]') | ||
1009 | 400 | |||
1010 | 401 | MAX_COLS = 8 | ||
1011 | 402 | |||
1012 | 427 | CONTACT_ICON_NAME = 'system-users' | 403 | CONTACT_ICON_NAME = 'system-users' |
1013 | 428 | FOLDER_ICON_NAME = 'folder' | 404 | FOLDER_ICON_NAME = 'folder' |
1014 | 429 | SHARE_ICON_NAME = 'folder-remote' | 405 | SHARE_ICON_NAME = 'folder-remote' |
1015 | 430 | ROW_HEADER = '<span font_size="large"><b>%s</b></span> ' \ | 406 | ROW_HEADER = '<span font_size="large"><b>%s</b></span> ' \ |
1016 | 431 | '<span foreground="grey">%s</span>' | 407 | '<span foreground="grey">%s</span>' |
1017 | 432 | ROOT = '%s - <span foreground="%s" font_size="small">%s</span>' | 408 | ROOT = '%s - <span foreground="%s" font_size="small">%s</span>' |
1018 | 433 | NO_VOLUMES = _('No folders to show.') | ||
1019 | 434 | 409 | ||
1020 | 435 | def __init__(self, main_window=None): | 410 | def __init__(self, main_window=None): |
1021 | 436 | UbuntuOneBin.__init__(self) | 411 | UbuntuOneBin.__init__(self) |
1022 | @@ -438,6 +413,11 @@ | |||
1023 | 438 | self.add(self.itself) | 413 | self.add(self.itself) |
1024 | 439 | self.show_all() | 414 | self.show_all() |
1025 | 440 | 415 | ||
1026 | 416 | # name, subscribed, icon name, show toggle, sensitive, icon size, | ||
1027 | 417 | # id, path | ||
1028 | 418 | self._empty_row = ('', False, '', False, False, gtk.ICON_SIZE_MENU, | ||
1029 | 419 | None, None) | ||
1030 | 420 | |||
1031 | 441 | self.backend.connect_to_signal('VolumesInfoReady', | 421 | self.backend.connect_to_signal('VolumesInfoReady', |
1032 | 442 | self.on_volumes_info_ready) | 422 | self.on_volumes_info_ready) |
1033 | 443 | self.backend.connect_to_signal('VolumesInfoError', | 423 | self.backend.connect_to_signal('VolumesInfoError', |
1034 | @@ -462,14 +442,16 @@ | |||
1035 | 462 | else: | 442 | else: |
1036 | 463 | self.on_success() | 443 | self.on_success() |
1037 | 464 | 444 | ||
1038 | 465 | # pylint: disable=W0612 | ||
1039 | 466 | # name, subscribed, icon name, show toggle, sensitive, icon size, id | ||
1040 | 467 | empty_row = ('', False, '', False, False, gtk.ICON_SIZE_MENU, None) | ||
1041 | 468 | |||
1042 | 469 | for name, free_bytes, volumes in info: | 445 | for name, free_bytes, volumes in info: |
1043 | 446 | if backend.ControlBackend.NAME_NOT_SET in name: | ||
1044 | 447 | name = self.NAME_NOT_SET | ||
1045 | 448 | |||
1046 | 470 | if name: | 449 | if name: |
1047 | 471 | name = name + "'s" | 450 | name = name + "'s" |
1048 | 472 | icon_name = self.SHARE_ICON_NAME | 451 | icon_name = self.SHARE_ICON_NAME |
1049 | 452 | |||
1050 | 453 | # we already added user folders, let's add an empty row | ||
1051 | 454 | treeiter = self.volumes_store.append(None, self._empty_row) | ||
1052 | 473 | else: | 455 | else: |
1053 | 474 | name = self.MY_FOLDERS | 456 | name = self.MY_FOLDERS |
1054 | 475 | icon_name = self.FOLDER_ICON_NAME | 457 | icon_name = self.FOLDER_ICON_NAME |
1055 | @@ -477,30 +459,33 @@ | |||
1056 | 477 | free_bytes_args = {'free_space': self.humanize(int(free_bytes))} | 459 | free_bytes_args = {'free_space': self.humanize(int(free_bytes))} |
1057 | 478 | row = (self.ROW_HEADER % (name, self.FREE_SPACE % free_bytes_args), | 460 | row = (self.ROW_HEADER % (name, self.FREE_SPACE % free_bytes_args), |
1058 | 479 | True, self.CONTACT_ICON_NAME, False, False, | 461 | True, self.CONTACT_ICON_NAME, False, False, |
1060 | 480 | gtk.ICON_SIZE_LARGE_TOOLBAR, None) | 462 | gtk.ICON_SIZE_LARGE_TOOLBAR, None, None) |
1061 | 481 | treeiter = self.volumes_store.append(None, row) | 463 | treeiter = self.volumes_store.append(None, row) |
1062 | 482 | 464 | ||
1063 | 483 | volumes.sort(key=operator.itemgetter('path')) | 465 | volumes.sort(key=operator.itemgetter('path')) |
1064 | 484 | for volume in volumes: | 466 | for volume in volumes: |
1065 | 485 | sensitive = True | 467 | sensitive = True |
1068 | 486 | path = self._process_path(volume['path']) | 468 | name = self._process_path(volume[u'path']) |
1069 | 487 | if volume['type'] == u'ROOT': | 469 | |
1070 | 470 | is_root = volume[u'type'] == backend.ControlBackend.ROOT_TYPE | ||
1071 | 471 | is_share = volume[u'type'] == backend.ControlBackend.SHARE_TYPE | ||
1072 | 472 | |||
1073 | 473 | if is_root: | ||
1074 | 488 | sensitive = False | 474 | sensitive = False |
1081 | 489 | path = self.ROOT % (path, ORANGE, self.ALWAYS_SUBSCRIBED) | 475 | name = self.ROOT % (name, ORANGE, self.ALWAYS_SUBSCRIBED) |
1082 | 490 | 476 | elif is_share: | |
1083 | 491 | row = (path, bool(volume['subscribed']), icon_name, True, | 477 | name = volume[u'name'] |
1084 | 492 | sensitive, gtk.ICON_SIZE_MENU, volume['volume_id']) | 478 | |
1085 | 493 | 479 | row = (name, bool(volume[u'subscribed']), icon_name, True, | |
1086 | 494 | if volume['type'] == u'ROOT': # root should go first! | 480 | sensitive, gtk.ICON_SIZE_MENU, volume['volume_id'], |
1087 | 481 | volume[u'path']) | ||
1088 | 482 | |||
1089 | 483 | if is_root: # root should go first! | ||
1090 | 495 | self.volumes_store.prepend(treeiter, row) | 484 | self.volumes_store.prepend(treeiter, row) |
1091 | 496 | else: | 485 | else: |
1092 | 497 | self.volumes_store.append(treeiter, row) | 486 | self.volumes_store.append(treeiter, row) |
1093 | 498 | 487 | ||
1099 | 499 | # When we display shares info, we'll need to smartly add | 488 | self.volumes_view.expand_all() |
1095 | 500 | # an empty row to the tree view to separate volume groups | ||
1096 | 501 | #treeiter = self.volumes_store.append(None, empty_row) | ||
1097 | 502 | |||
1098 | 503 | self.volumes_view.expand_row(0, True) | ||
1100 | 504 | self.volumes_view.show_all() | 489 | self.volumes_view.show_all() |
1101 | 505 | 490 | ||
1102 | 506 | self.is_processing = False | 491 | self.is_processing = False |
1103 | @@ -534,6 +519,12 @@ | |||
1104 | 534 | 519 | ||
1105 | 535 | self.is_processing = True | 520 | self.is_processing = True |
1106 | 536 | 521 | ||
1107 | 522 | def on_volumes_view_row_activated(self, widget, path, *args, **kwargs): | ||
1108 | 523 | """The user double clicked on a row.""" | ||
1109 | 524 | treeiter = self.volumes_store.get_iter(path) | ||
1110 | 525 | volume_path = self.volumes_store.get_value(treeiter, 7) | ||
1111 | 526 | uri_hook(None, FILE_URI_PREFIX + volume_path) | ||
1112 | 527 | |||
1113 | 537 | def load(self): | 528 | def load(self): |
1114 | 538 | """Load the volume list.""" | 529 | """Load the volume list.""" |
1115 | 539 | self.backend.volumes_info(reply_handler=NO_OP, | 530 | self.backend.volumes_info(reply_handler=NO_OP, |
1116 | @@ -739,7 +730,8 @@ | |||
1117 | 739 | gobject.TYPE_NONE, ()), | 730 | gobject.TYPE_NONE, ()), |
1118 | 740 | } | 731 | } |
1119 | 741 | 732 | ||
1121 | 742 | TITLE = _('The devices synced with your personal cloud are listed below.') | 733 | TITLE = _('The devices connected with your personal cloud are listed ' |
1122 | 734 | 'below.') | ||
1123 | 743 | NO_DEVICES = _('No devices to show.') | 735 | NO_DEVICES = _('No devices to show.') |
1124 | 744 | CONFIRM_REMOVE = _('Are you sure you want to remove this device ' | 736 | CONFIRM_REMOVE = _('Are you sure you want to remove this device ' |
1125 | 745 | 'from Ubuntu One?') | 737 | 'from Ubuntu One?') |
1126 | @@ -1270,6 +1262,8 @@ | |||
1127 | 1270 | } | 1262 | } |
1128 | 1271 | 1263 | ||
1129 | 1272 | QUOTA_LABEL = _('%(used)s used of %(total)s (%(percentage).1f%%)') | 1264 | QUOTA_LABEL = _('%(used)s used of %(total)s (%(percentage).1f%%)') |
1130 | 1265 | DASHBOARD_BUTTON_NAME = 'Account' | ||
1131 | 1266 | DEVICES_BUTTON_NAME = 'Devices' | ||
1132 | 1273 | 1267 | ||
1133 | 1274 | def __init__(self, main_window=None): | 1268 | def __init__(self, main_window=None): |
1134 | 1275 | gtk.VBox.__init__(self) | 1269 | gtk.VBox.__init__(self) |
1135 | @@ -1287,6 +1281,7 @@ | |||
1136 | 1287 | self.quota_progressbar.set_sensitive(False) | 1281 | self.quota_progressbar.set_sensitive(False) |
1137 | 1288 | self.quota_label = LabelLoading(LOADING, fg_color=DEFAULT_FG) | 1282 | self.quota_label = LabelLoading(LOADING, fg_color=DEFAULT_FG) |
1138 | 1289 | self.quota_box.pack_start(self.quota_label, expand=False) | 1283 | self.quota_box.pack_start(self.quota_label, expand=False) |
1139 | 1284 | self.quota_box.reorder_child(self.quota_label, 0) | ||
1140 | 1290 | 1285 | ||
1141 | 1291 | self.status_label = FileSyncStatus() | 1286 | self.status_label = FileSyncStatus() |
1142 | 1292 | self.status_box.pack_end(self.status_label, expand=False) | 1287 | self.status_box.pack_end(self.status_label, expand=False) |
1143 | @@ -1309,9 +1304,13 @@ | |||
1144 | 1309 | gtk.gdk.Color(DEFAULT_FG)) | 1304 | gtk.gdk.Color(DEFAULT_FG)) |
1145 | 1310 | self.notebook.insert_page(getattr(self, tab), position=page_num) | 1305 | self.notebook.insert_page(getattr(self, tab), position=page_num) |
1146 | 1311 | 1306 | ||
1147 | 1307 | self.dashboard_button.set_name(self.DASHBOARD_BUTTON_NAME) | ||
1148 | 1308 | |||
1149 | 1312 | self.volumes_button.connect('clicked', lambda b: self.volumes.load()) | 1309 | self.volumes_button.connect('clicked', lambda b: self.volumes.load()) |
1150 | 1310 | self.services_button.connect('clicked', lambda b: self.services.load()) | ||
1151 | 1311 | |||
1152 | 1312 | self.devices_button.set_name(self.DEVICES_BUTTON_NAME) | ||
1153 | 1313 | self.devices_button.connect('clicked', lambda b: self.devices.load()) | 1313 | self.devices_button.connect('clicked', lambda b: self.devices.load()) |
1154 | 1314 | self.services_button.connect('clicked', lambda b: self.services.load()) | ||
1155 | 1315 | self.devices.connect('local-device-removed', | 1314 | self.devices.connect('local-device-removed', |
1156 | 1316 | lambda widget: self.emit('local-device-removed')) | 1315 | lambda widget: self.emit('local-device-removed')) |
1157 | 1317 | 1316 | ||
1158 | @@ -1397,7 +1396,7 @@ | |||
1159 | 1397 | class ControlPanelWindow(gtk.Window): | 1396 | class ControlPanelWindow(gtk.Window): |
1160 | 1398 | """The main window for the Ubuntu One control panel.""" | 1397 | """The main window for the Ubuntu One control panel.""" |
1161 | 1399 | 1398 | ||
1163 | 1400 | TITLE = _('%(app_name)s Dashboard') | 1399 | TITLE = _('%(app_name)s Control Panel') |
1164 | 1401 | 1400 | ||
1165 | 1402 | def __init__(self, switch_to=None): | 1401 | def __init__(self, switch_to=None): |
1166 | 1403 | super(ControlPanelWindow, self).__init__() | 1402 | super(ControlPanelWindow, self).__init__() |
1167 | 1404 | 1403 | ||
1168 | === modified file 'ubuntuone/controlpanel/gtk/tests/__init__.py' | |||
1169 | --- ubuntuone/controlpanel/gtk/tests/__init__.py 2011-01-25 19:08:59 +0000 | |||
1170 | +++ ubuntuone/controlpanel/gtk/tests/__init__.py 2011-02-12 03:22:55 +0000 | |||
1171 | @@ -45,11 +45,11 @@ | |||
1172 | 45 | ] | 45 | ] |
1173 | 46 | 46 | ||
1174 | 47 | FAKE_SHARES_INFO = [ | 47 | FAKE_SHARES_INFO = [ |
1176 | 48 | {u'volume_id': u'1234', | 48 | {u'volume_id': u'1234', u'name': u'do', |
1177 | 49 | u'path': u'/home/tester/.local/share/ubuntuone/shares/do from Other User', | 49 | u'path': u'/home/tester/.local/share/ubuntuone/shares/do from Other User', |
1178 | 50 | u'subscribed': u'', u'type': u'SHARE'}, | 50 | u'subscribed': u'', u'type': u'SHARE'}, |
1179 | 51 | 51 | ||
1181 | 52 | {u'volume_id': u'5678', | 52 | {u'volume_id': u'5678', u'name': u're', |
1182 | 53 | u'path': u'/home/tester/.local/share/ubuntuone/shares/re from Other User', | 53 | u'path': u'/home/tester/.local/share/ubuntuone/shares/re from Other User', |
1183 | 54 | u'subscribed': u'True', u'type': u'SHARE'}, | 54 | u'subscribed': u'True', u'type': u'SHARE'}, |
1184 | 55 | ] | 55 | ] |
1185 | 56 | 56 | ||
1186 | === modified file 'ubuntuone/controlpanel/gtk/tests/test_gui.py' | |||
1187 | --- ubuntuone/controlpanel/gtk/tests/test_gui.py 2011-01-25 19:08:59 +0000 | |||
1188 | +++ ubuntuone/controlpanel/gtk/tests/test_gui.py 2011-02-12 03:22:55 +0000 | |||
1189 | @@ -27,7 +27,7 @@ | |||
1190 | 27 | from ubuntuone.controlpanel.gtk import gui | 27 | from ubuntuone.controlpanel.gtk import gui |
1191 | 28 | from ubuntuone.controlpanel.gtk.tests import (FAKE_ACCOUNT_INFO, | 28 | from ubuntuone.controlpanel.gtk.tests import (FAKE_ACCOUNT_INFO, |
1192 | 29 | FAKE_DEVICE_INFO, FAKE_DEVICES_INFO, | 29 | FAKE_DEVICE_INFO, FAKE_DEVICES_INFO, |
1194 | 30 | FAKE_VOLUMES_INFO, FAKE_REPLICATIONS_INFO, USER_HOME, | 30 | FAKE_VOLUMES_INFO, FAKE_REPLICATIONS_INFO, ROOT, USER_HOME, |
1195 | 31 | FakedNMState, FakedSSOBackend, FakedSessionBus, FakedInterface, | 31 | FakedNMState, FakedSSOBackend, FakedSessionBus, FakedInterface, |
1196 | 32 | FakedPackageManager, FakedConfirmDialog, | 32 | FakedPackageManager, FakedConfirmDialog, |
1197 | 33 | ) | 33 | ) |
1198 | @@ -82,21 +82,6 @@ | |||
1199 | 82 | pb = gui.gtk.gdk.pixbuf_new_from_file(gui.get_data_file(filename)) | 82 | pb = gui.gtk.gdk.pixbuf_new_from_file(gui.get_data_file(filename)) |
1200 | 83 | self.assertEqual(image.get_pixbuf().get_pixels(), pb.get_pixels()) | 83 | self.assertEqual(image.get_pixbuf().get_pixels(), pb.get_pixels()) |
1201 | 84 | 84 | ||
1202 | 85 | def assert_messages_equal(self, widget, msgs): | ||
1203 | 86 | """Check that 'widget' has all the entries in 'msgs'.""" | ||
1204 | 87 | children = list(reversed(widget.get_children())) | ||
1205 | 88 | self.assertEqual(len(children), len(msgs)) | ||
1206 | 89 | for label, msg in zip(reversed(children), msgs): | ||
1207 | 90 | full_msg = self.ui.BULLET + ' ' + msg | ||
1208 | 91 | self.assertTrue(label.get_visible()) | ||
1209 | 92 | self.assertEqual(label.get_property('xalign'), 0) | ||
1210 | 93 | self.assertEqual(label.get_property('wrap'), True) | ||
1211 | 94 | self.assertEqual(label.get_label(), full_msg) | ||
1212 | 95 | |||
1213 | 96 | expected = gui.gtk.Label() | ||
1214 | 97 | expected.set_markup(full_msg) | ||
1215 | 98 | self.assertEqual(label.get_text(), expected.get_text()) | ||
1216 | 99 | |||
1217 | 100 | def assert_backend_called(self, method_name, args, backend=None): | 85 | def assert_backend_called(self, method_name, args, backend=None): |
1218 | 101 | """Check that the control panel backend 'method_name' was called.""" | 86 | """Check that the control panel backend 'method_name' was called.""" |
1219 | 102 | if backend is None: | 87 | if backend is None: |
1220 | @@ -392,7 +377,7 @@ | |||
1221 | 392 | """The test suite for the overview panel.""" | 377 | """The test suite for the overview panel.""" |
1222 | 393 | 378 | ||
1223 | 394 | klass = gui.OverviewPanel | 379 | klass = gui.OverviewPanel |
1225 | 395 | kwargs = {'messages': None, 'main_window': gui.gtk.Window()} | 380 | kwargs = {'main_window': gui.gtk.Window()} |
1226 | 396 | ui_filename = 'overview.ui' | 381 | ui_filename = 'overview.ui' |
1227 | 397 | 382 | ||
1228 | 398 | def test_is_a_greyable_bin(self): | 383 | def test_is_a_greyable_bin(self): |
1229 | @@ -561,10 +546,7 @@ | |||
1230 | 561 | class OverwiewPanelNoCredsTestCase(OverwiewPanelTestCase): | 546 | class OverwiewPanelNoCredsTestCase(OverwiewPanelTestCase): |
1231 | 562 | """The test suite for the overview panel when no credentials are found.""" | 547 | """The test suite for the overview panel when no credentials are found.""" |
1232 | 563 | 548 | ||
1233 | 564 | messages = None | ||
1234 | 565 | |||
1235 | 566 | def setUp(self): | 549 | def setUp(self): |
1236 | 567 | self.kwargs['messages'] = self.messages | ||
1237 | 568 | super(OverwiewPanelNoCredsTestCase, self).setUp() | 550 | super(OverwiewPanelNoCredsTestCase, self).setUp() |
1238 | 569 | self.ui.on_credentials_not_found(gui.U1_APP_NAME) | 551 | self.ui.on_credentials_not_found(gui.U1_APP_NAME) |
1239 | 570 | 552 | ||
1240 | @@ -581,10 +563,6 @@ | |||
1241 | 581 | """There is an image attribute and is correct.""" | 563 | """There is an image attribute and is correct.""" |
1242 | 582 | self.assert_image_equal(self.ui.image, 'overview.png') | 564 | self.assert_image_equal(self.ui.image, 'overview.png') |
1243 | 583 | 565 | ||
1244 | 584 | def test_messages(self): | ||
1245 | 585 | """If no messages are passed, the default list is used.""" | ||
1246 | 586 | self.assert_messages_equal(self.ui.messages, gui.OVERVIEW_MSGS) | ||
1247 | 587 | |||
1248 | 588 | def test_join_now_is_default_widget(self): | 566 | def test_join_now_is_default_widget(self): |
1249 | 589 | """The join now button is the default widget.""" | 567 | """The join now button is the default widget.""" |
1250 | 590 | self.assertTrue(self.ui.join_now_button.get_property('can_default')) | 568 | self.assertTrue(self.ui.join_now_button.get_property('can_default')) |
1251 | @@ -683,18 +661,6 @@ | |||
1252 | 683 | self.assertTrue(self.ui.connect_button.is_sensitive()) | 661 | self.assertTrue(self.ui.connect_button.is_sensitive()) |
1253 | 684 | 662 | ||
1254 | 685 | 663 | ||
1255 | 686 | class OverwiewPanelMessagesTestCase(OverwiewPanelTestCase): | ||
1256 | 687 | """The test suite for the overview panel when messages are set.""" | ||
1257 | 688 | |||
1258 | 689 | messages = ['Test me', 'A little bit more'] | ||
1259 | 690 | |||
1260 | 691 | |||
1261 | 692 | class OverwiewPanelMarkupMessagesTestCase(OverwiewPanelTestCase): | ||
1262 | 693 | """The test suite for the overview panel when markup messages are set.""" | ||
1263 | 694 | |||
1264 | 695 | messages = ['<small>Test me</small>', 'A <b>little</b> bit more'] | ||
1265 | 696 | |||
1266 | 697 | |||
1267 | 698 | class DashboardTestCase(ControlPanelMixinTestCase): | 664 | class DashboardTestCase(ControlPanelMixinTestCase): |
1268 | 699 | """The test suite for the dashboard panel.""" | 665 | """The test suite for the dashboard panel.""" |
1269 | 700 | 666 | ||
1270 | @@ -835,7 +801,8 @@ | |||
1271 | 835 | """The volumes info is processed when ready.""" | 801 | """The volumes info is processed when ready.""" |
1272 | 836 | self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO) | 802 | self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO) |
1273 | 837 | 803 | ||
1275 | 838 | self.assertEqual(len(FAKE_VOLUMES_INFO), len(self.ui.volumes_store)) | 804 | self.assertEqual(len(FAKE_VOLUMES_INFO) + 1, # count the empty row |
1276 | 805 | len(self.ui.volumes_store)) | ||
1277 | 839 | treeiter = self.ui.volumes_store.get_iter_root() | 806 | treeiter = self.ui.volumes_store.get_iter_root() |
1278 | 840 | for name, free_bytes, volumes in FAKE_VOLUMES_INFO: | 807 | for name, free_bytes, volumes in FAKE_VOLUMES_INFO: |
1279 | 841 | name = "%s's" % name if name else self.ui.MY_FOLDERS | 808 | name = "%s's" % name if name else self.ui.MY_FOLDERS |
1280 | @@ -843,7 +810,8 @@ | |||
1281 | 843 | header = (name, self.ui.FREE_SPACE % {'free_space': free_bytes}) | 810 | header = (name, self.ui.FREE_SPACE % {'free_space': free_bytes}) |
1282 | 844 | 811 | ||
1283 | 845 | # check parent row | 812 | # check parent row |
1285 | 846 | row = self.ui.volumes_store.get(treeiter, *xrange(7)) | 813 | row = self.ui.volumes_store.get(treeiter, |
1286 | 814 | *xrange(self.ui.MAX_COLS)) | ||
1287 | 847 | 815 | ||
1288 | 848 | self.assertEqual(row[0], self.ui.ROW_HEADER % header) | 816 | self.assertEqual(row[0], self.ui.ROW_HEADER % header) |
1289 | 849 | self.assertTrue(row[1], 'parent will always be subscribed') | 817 | self.assertTrue(row[1], 'parent will always be subscribed') |
1290 | @@ -852,6 +820,7 @@ | |||
1291 | 852 | self.assertFalse(row[4], 'toggle should be non sensitive.') | 820 | self.assertFalse(row[4], 'toggle should be non sensitive.') |
1292 | 853 | self.assertEqual(row[5], gui.gtk.ICON_SIZE_LARGE_TOOLBAR) | 821 | self.assertEqual(row[5], gui.gtk.ICON_SIZE_LARGE_TOOLBAR) |
1293 | 854 | self.assertEqual(row[6], None) | 822 | self.assertEqual(row[6], None) |
1294 | 823 | self.assertEqual(row[7], None) | ||
1295 | 855 | 824 | ||
1296 | 856 | # check children | 825 | # check children |
1297 | 857 | self.assertEqual(len(volumes), | 826 | self.assertEqual(len(volumes), |
1298 | @@ -860,7 +829,8 @@ | |||
1299 | 860 | 829 | ||
1300 | 861 | sorted_vols = sorted(volumes, key=gui.operator.itemgetter('path')) | 830 | sorted_vols = sorted(volumes, key=gui.operator.itemgetter('path')) |
1301 | 862 | for volume in sorted_vols: | 831 | for volume in sorted_vols: |
1303 | 863 | row = self.ui.volumes_store.get(childiter, *xrange(7)) | 832 | row = self.ui.volumes_store.get(childiter, |
1304 | 833 | *xrange(self.ui.MAX_COLS)) | ||
1305 | 864 | 834 | ||
1306 | 865 | sensitive = True | 835 | sensitive = True |
1307 | 866 | path = volume['path'].replace(USER_HOME + '/', '') | 836 | path = volume['path'].replace(USER_HOME + '/', '') |
1308 | @@ -868,6 +838,8 @@ | |||
1309 | 868 | sensitive = False | 838 | sensitive = False |
1310 | 869 | path = self.ui.ROOT % (path, gui.ORANGE, | 839 | path = self.ui.ROOT % (path, gui.ORANGE, |
1311 | 870 | self.ui.ALWAYS_SUBSCRIBED) | 840 | self.ui.ALWAYS_SUBSCRIBED) |
1312 | 841 | elif volume['type'] == 'SHARE': | ||
1313 | 842 | path = volume['name'] | ||
1314 | 871 | 843 | ||
1315 | 872 | self.assertEqual(row[0], path) | 844 | self.assertEqual(row[0], path) |
1316 | 873 | self.assertEqual(row[1], bool(volume['subscribed'])) | 845 | self.assertEqual(row[1], bool(volume['subscribed'])) |
1317 | @@ -879,17 +851,28 @@ | |||
1318 | 879 | self.assertEqual(row[4], sensitive) | 851 | self.assertEqual(row[4], sensitive) |
1319 | 880 | self.assertEqual(row[5], gui.gtk.ICON_SIZE_MENU) | 852 | self.assertEqual(row[5], gui.gtk.ICON_SIZE_MENU) |
1320 | 881 | self.assertEqual(row[6], volume['volume_id']) | 853 | self.assertEqual(row[6], volume['volume_id']) |
1321 | 854 | self.assertEqual(row[7], volume['path']) | ||
1322 | 882 | 855 | ||
1323 | 883 | childiter = self.ui.volumes_store.iter_next(childiter) | 856 | childiter = self.ui.volumes_store.iter_next(childiter) |
1324 | 884 | 857 | ||
1325 | 885 | treeiter = self.ui.volumes_store.iter_next(treeiter) | 858 | treeiter = self.ui.volumes_store.iter_next(treeiter) |
1326 | 886 | 859 | ||
1327 | 860 | if treeiter is not None: | ||
1328 | 861 | # skip the empty row | ||
1329 | 862 | row = self.ui.volumes_store.get(treeiter, | ||
1330 | 863 | *xrange(self.ui.MAX_COLS)) | ||
1331 | 864 | self.assertEqual(row, self.ui._empty_row) | ||
1332 | 865 | |||
1333 | 866 | # grab next non-empty row | ||
1334 | 867 | treeiter = self.ui.volumes_store.iter_next(treeiter) | ||
1335 | 868 | |||
1336 | 887 | def test_on_volumes_info_ready_clears_the_list(self): | 869 | def test_on_volumes_info_ready_clears_the_list(self): |
1337 | 888 | """The old volumes info is cleared before updated.""" | 870 | """The old volumes info is cleared before updated.""" |
1338 | 889 | self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO) | 871 | self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO) |
1339 | 890 | self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO) | 872 | self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO) |
1340 | 891 | 873 | ||
1342 | 892 | self.assertEqual(len(self.ui.volumes_store), len(FAKE_VOLUMES_INFO)) | 874 | self.assertEqual(len(FAKE_VOLUMES_INFO) + 1, |
1343 | 875 | len(self.ui.volumes_store)) | ||
1344 | 893 | 876 | ||
1345 | 894 | def test_on_volumes_info_ready_with_no_volumes(self): | 877 | def test_on_volumes_info_ready_with_no_volumes(self): |
1346 | 895 | """When there are no volumes, a notification is shown.""" | 878 | """When there are no volumes, a notification is shown.""" |
1347 | @@ -917,7 +900,9 @@ | |||
1348 | 917 | """Clicking on 'subscribed' updates the folder subscription.""" | 900 | """Clicking on 'subscribed' updates the folder subscription.""" |
1349 | 918 | self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO) | 901 | self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO) |
1350 | 919 | 902 | ||
1352 | 920 | for parent, (_, _, volumes) in enumerate(FAKE_VOLUMES_INFO): | 903 | real_rows = len(FAKE_VOLUMES_INFO) |
1353 | 904 | data = zip(range(real_rows)[::2], FAKE_VOLUMES_INFO) # skip emtpy rows | ||
1354 | 905 | for parent, (_, _, volumes) in data: | ||
1355 | 921 | 906 | ||
1356 | 922 | sorted_vols = sorted(volumes, key=gui.operator.itemgetter('path')) | 907 | sorted_vols = sorted(volumes, key=gui.operator.itemgetter('path')) |
1357 | 923 | for child, volume in enumerate(sorted_vols): | 908 | for child, volume in enumerate(sorted_vols): |
1358 | @@ -964,6 +949,17 @@ | |||
1359 | 964 | # reload folders list to sanitize the info in volumes_store | 949 | # reload folders list to sanitize the info in volumes_store |
1360 | 965 | self.assertTrue(self._called, ((), {})) | 950 | self.assertTrue(self._called, ((), {})) |
1361 | 966 | 951 | ||
1362 | 952 | def test_clicking_on_row_opens_folder(self): | ||
1363 | 953 | """The folder activated is opened.""" | ||
1364 | 954 | self.patch(gui, 'uri_hook', self._set_called) | ||
1365 | 955 | self.ui.on_volumes_info_ready(FAKE_VOLUMES_INFO) | ||
1366 | 956 | |||
1367 | 957 | self.ui.volumes_view.row_activated('0:0', | ||
1368 | 958 | self.ui.volumes_view.get_column(0)) | ||
1369 | 959 | |||
1370 | 960 | self.assertEqual(self._called, | ||
1371 | 961 | ((None, gui.FILE_URI_PREFIX + ROOT['path']), {})) | ||
1372 | 962 | |||
1373 | 967 | 963 | ||
1374 | 968 | class DeviceTestCase(ControlPanelMixinTestCase): | 964 | class DeviceTestCase(ControlPanelMixinTestCase): |
1375 | 969 | """The test suite for the device widget.""" | 965 | """The test suite for the device widget.""" |
1376 | @@ -2358,3 +2354,13 @@ | |||
1377 | 2358 | self.ui.devices.emit('local-device-removed') | 2354 | self.ui.devices.emit('local-device-removed') |
1378 | 2359 | 2355 | ||
1379 | 2360 | self.assertEqual(self._called, ((self.ui,), {})) | 2356 | self.assertEqual(self._called, ((self.ui,), {})) |
1380 | 2357 | |||
1381 | 2358 | def test_dashboard_button_name(self): | ||
1382 | 2359 | """The dashboard_button widget has the proper name.""" | ||
1383 | 2360 | self.assertEqual(self.ui.dashboard_button.get_name(), | ||
1384 | 2361 | self.ui.DASHBOARD_BUTTON_NAME) | ||
1385 | 2362 | |||
1386 | 2363 | def test_devices_button_name(self): | ||
1387 | 2364 | """The devices_button widget has the proper name.""" | ||
1388 | 2365 | self.assertEqual(self.ui.devices_button.get_name(), | ||
1389 | 2366 | self.ui.DEVICES_BUTTON_NAME) | ||
1390 | 2361 | 2367 | ||
1391 | === modified file 'ubuntuone/controlpanel/integrationtests/test_dbus_client_sd.py' | |||
1392 | --- ubuntuone/controlpanel/integrationtests/test_dbus_client_sd.py 2011-01-25 19:08:59 +0000 | |||
1393 | +++ ubuntuone/controlpanel/integrationtests/test_dbus_client_sd.py 2011-02-12 03:22:55 +0000 | |||
1394 | @@ -19,9 +19,11 @@ | |||
1395 | 19 | 19 | ||
1396 | 20 | """Tests for the DBus service when accessing SyncDaemon.""" | 20 | """Tests for the DBus service when accessing SyncDaemon.""" |
1397 | 21 | 21 | ||
1398 | 22 | import uuid | ||
1399 | 23 | |||
1400 | 22 | import dbus | 24 | import dbus |
1401 | 23 | 25 | ||
1403 | 24 | from twisted.internet.defer import inlineCallbacks | 26 | from twisted.internet.defer import inlineCallbacks, returnValue |
1404 | 25 | 27 | ||
1405 | 26 | from ubuntuone.controlpanel import dbus_client | 28 | from ubuntuone.controlpanel import dbus_client |
1406 | 27 | from ubuntuone.controlpanel.dbus_client import sd_dbus_iface | 29 | from ubuntuone.controlpanel.dbus_client import sd_dbus_iface |
1407 | @@ -34,6 +36,8 @@ | |||
1408 | 34 | "download": "838", | 36 | "download": "838", |
1409 | 35 | } | 37 | } |
1410 | 36 | 38 | ||
1411 | 39 | SHARES = {} | ||
1412 | 40 | |||
1413 | 37 | # pylint, you have to go to decorator's school | 41 | # pylint, you have to go to decorator's school |
1414 | 38 | # pylint: disable=C0322 | 42 | # pylint: disable=C0322 |
1415 | 39 | 43 | ||
1416 | @@ -302,7 +306,7 @@ | |||
1417 | 302 | 306 | ||
1418 | 303 | 307 | ||
1419 | 304 | class FoldersTestCase(DBusClientTestCase): | 308 | class FoldersTestCase(DBusClientTestCase): |
1421 | 305 | """Test for the volumes dbus client methods.""" | 309 | """Test for the shares dbus client methods.""" |
1422 | 306 | 310 | ||
1423 | 307 | def setUp(self): | 311 | def setUp(self): |
1424 | 308 | super(FoldersTestCase, self).setUp() | 312 | super(FoldersTestCase, self).setUp() |
1425 | @@ -379,7 +383,7 @@ | |||
1426 | 379 | try: | 383 | try: |
1427 | 380 | yield dbus_client.subscribe_folder(fid) | 384 | yield dbus_client.subscribe_folder(fid) |
1428 | 381 | except dbus_client.VolumesError, e: | 385 | except dbus_client.VolumesError, e: |
1430 | 382 | self.assertEqual(e[0], {'id': fid}) | 386 | self.assertEqual(e[0], fid) |
1431 | 383 | else: | 387 | else: |
1432 | 384 | self.fail('dbus_client.subscribe_folder should be errbacking') | 388 | self.fail('dbus_client.subscribe_folder should be errbacking') |
1433 | 385 | 389 | ||
1434 | @@ -405,11 +409,159 @@ | |||
1435 | 405 | try: | 409 | try: |
1436 | 406 | yield dbus_client.unsubscribe_folder(fid) | 410 | yield dbus_client.unsubscribe_folder(fid) |
1437 | 407 | except dbus_client.VolumesError, e: | 411 | except dbus_client.VolumesError, e: |
1439 | 408 | self.assertEqual(e[0], {'id': fid}) | 412 | self.assertEqual(e[0], fid) |
1440 | 409 | else: | 413 | else: |
1441 | 410 | self.fail('dbus_client.unsubscribe_folder should be errbacking') | 414 | self.fail('dbus_client.unsubscribe_folder should be errbacking') |
1442 | 411 | 415 | ||
1443 | 412 | 416 | ||
1444 | 417 | class FakedSyncDaemonTool(object): | ||
1445 | 418 | """Fake the FakedSyncDaemonTool.""" | ||
1446 | 419 | |||
1447 | 420 | def __init__(self, bus): | ||
1448 | 421 | """New instance.""" | ||
1449 | 422 | |||
1450 | 423 | def _set_share_attr(self, share_id, attr, value): | ||
1451 | 424 | """Set values to shares.""" | ||
1452 | 425 | if share_id not in SHARES: | ||
1453 | 426 | raise dbus.DBusException('share_id not in SHARES.') | ||
1454 | 427 | |||
1455 | 428 | value = sd_dbus_iface.bool_str(value) | ||
1456 | 429 | SHARES[share_id][attr] = value | ||
1457 | 430 | return share_id | ||
1458 | 431 | |||
1459 | 432 | @inlineCallbacks | ||
1460 | 433 | def accept_share(self, share_id): | ||
1461 | 434 | """Accept the share with id: share_id.""" | ||
1462 | 435 | yield self._set_share_attr(share_id, u'accepted', True) | ||
1463 | 436 | |||
1464 | 437 | @inlineCallbacks | ||
1465 | 438 | def reject_share(self, share_id): | ||
1466 | 439 | """Reject the share with id: share_id.""" | ||
1467 | 440 | yield self._set_share_attr(share_id, u'accepted', False) | ||
1468 | 441 | |||
1469 | 442 | @inlineCallbacks | ||
1470 | 443 | def subscribe_share(self, share_id): | ||
1471 | 444 | """Subscribe to a share given its id.""" | ||
1472 | 445 | yield self._set_share_attr(share_id, u'subscribed', True) | ||
1473 | 446 | |||
1474 | 447 | @inlineCallbacks | ||
1475 | 448 | def unsubscribe_share(self, share_id): | ||
1476 | 449 | """Unsubscribe from a share given its id.""" | ||
1477 | 450 | yield self._set_share_attr(share_id, u'subscribed', False) | ||
1478 | 451 | |||
1479 | 452 | @inlineCallbacks | ||
1480 | 453 | def get_shares(self): | ||
1481 | 454 | """Get the list of shares (accepted or not).""" | ||
1482 | 455 | result = yield SHARES.values() | ||
1483 | 456 | returnValue(sorted(result)) | ||
1484 | 457 | |||
1485 | 458 | @inlineCallbacks | ||
1486 | 459 | def refresh_shares(self): | ||
1487 | 460 | """Call refresh_shares method via DBus.""" | ||
1488 | 461 | yield | ||
1489 | 462 | |||
1490 | 463 | @classmethod | ||
1491 | 464 | def create_share(cls, name, accepted=False, subscribed=False): | ||
1492 | 465 | """Add a new share (fake).""" | ||
1493 | 466 | sid = unicode(uuid.uuid4()) | ||
1494 | 467 | path = u'/home/tester/.hidden/shares/%s from The Othr User' % name | ||
1495 | 468 | share = { | ||
1496 | 469 | u'name': name, u'subscribed': sd_dbus_iface.bool_str(subscribed), | ||
1497 | 470 | u'accepted': sd_dbus_iface.bool_str(accepted), | ||
1498 | 471 | u'generation': u'36', u'type': u'Share', | ||
1499 | 472 | u'node_id': u'ca3a1cec-09d2-485e-9685-1a5180bd6441', | ||
1500 | 473 | u'volume_id': sid, u'access_level': u'View', | ||
1501 | 474 | u'other_username': u'https://login.ubuntu.com/+id/nHRnYmz', | ||
1502 | 475 | u'other_visible_name': u'The Other User', | ||
1503 | 476 | u'free_bytes': u'2146703403', u'path': path, | ||
1504 | 477 | } | ||
1505 | 478 | SHARES[sid] = share | ||
1506 | 479 | return share | ||
1507 | 480 | |||
1508 | 481 | |||
1509 | 482 | class SharesTestCase(DBusClientTestCase): | ||
1510 | 483 | """Test for the shares dbus client methods.""" | ||
1511 | 484 | |||
1512 | 485 | def setUp(self): | ||
1513 | 486 | super(SharesTestCase, self).setUp() | ||
1514 | 487 | self.patch(dbus_client, 'SyncDaemonTool', FakedSyncDaemonTool) | ||
1515 | 488 | SHARES.clear() | ||
1516 | 489 | |||
1517 | 490 | @inlineCallbacks | ||
1518 | 491 | def test_get_shares(self): | ||
1519 | 492 | """Retrieve shares info list.""" | ||
1520 | 493 | share1 = FakedSyncDaemonTool.create_share(name='first, test me!') | ||
1521 | 494 | share2 = FakedSyncDaemonTool.create_share(name='and test me more!', | ||
1522 | 495 | accepted=True) | ||
1523 | 496 | share3 = FakedSyncDaemonTool.create_share(name='last but not least', | ||
1524 | 497 | accepted=True, subscribed=True) | ||
1525 | 498 | |||
1526 | 499 | result = yield dbus_client.get_shares() | ||
1527 | 500 | |||
1528 | 501 | self.assertEqual(result, sorted([share1, share2, share3])) | ||
1529 | 502 | |||
1530 | 503 | @inlineCallbacks | ||
1531 | 504 | def test_get_shares_error(self): | ||
1532 | 505 | """Handle error when retrieving current syncdaemon status.""" | ||
1533 | 506 | self.patch(FakedSyncDaemonTool, 'get_shares', self.fail) | ||
1534 | 507 | try: | ||
1535 | 508 | yield dbus_client.get_shares() | ||
1536 | 509 | except: # pylint: disable=W0702 | ||
1537 | 510 | pass # test passes! | ||
1538 | 511 | else: | ||
1539 | 512 | self.fail('dbus_client.get_shares should be errbacking') | ||
1540 | 513 | |||
1541 | 514 | @inlineCallbacks | ||
1542 | 515 | def test_subscribe_share(self): | ||
1543 | 516 | """Subscribe to a share.""" | ||
1544 | 517 | share = FakedSyncDaemonTool.create_share(name='to be subscribed', | ||
1545 | 518 | accepted=True, subscribed=False) | ||
1546 | 519 | sid = share['volume_id'] | ||
1547 | 520 | |||
1548 | 521 | yield dbus_client.subscribe_share(sid) | ||
1549 | 522 | |||
1550 | 523 | result = yield dbus_client.get_shares() | ||
1551 | 524 | expected, = filter(lambda share: share['volume_id'] == sid, result) | ||
1552 | 525 | self.assertEqual(expected['subscribed'], 'True') | ||
1553 | 526 | |||
1554 | 527 | @inlineCallbacks | ||
1555 | 528 | def test_subscribe_share_error(self): | ||
1556 | 529 | """Subscribe to a share.""" | ||
1557 | 530 | sid = u'does not exist' | ||
1558 | 531 | try: | ||
1559 | 532 | yield dbus_client.subscribe_share(sid) | ||
1560 | 533 | except dbus_client.VolumesError, e: | ||
1561 | 534 | self.assertEqual(e[0], sid) | ||
1562 | 535 | else: | ||
1563 | 536 | self.fail('dbus_client.subscribe_share should be errbacking') | ||
1564 | 537 | |||
1565 | 538 | @inlineCallbacks | ||
1566 | 539 | def test_unsubscribe_share(self): | ||
1567 | 540 | """Unsubscribe to a share.""" | ||
1568 | 541 | share = FakedSyncDaemonTool.create_share(name='to be unsubscribed', | ||
1569 | 542 | accepted=True, subscribed=True) | ||
1570 | 543 | sid = share['volume_id'] | ||
1571 | 544 | yield dbus_client.subscribe_share(sid) | ||
1572 | 545 | # share is subscribed | ||
1573 | 546 | |||
1574 | 547 | yield dbus_client.unsubscribe_share(sid) | ||
1575 | 548 | |||
1576 | 549 | result = yield dbus_client.get_shares() | ||
1577 | 550 | expected, = filter(lambda share: share['volume_id'] == sid, result) | ||
1578 | 551 | self.assertEqual(expected['subscribed'], '') | ||
1579 | 552 | |||
1580 | 553 | @inlineCallbacks | ||
1581 | 554 | def test_unsubscribe_share_error(self): | ||
1582 | 555 | """Unsubscribe to a share.""" | ||
1583 | 556 | sid = u'does not exist' | ||
1584 | 557 | try: | ||
1585 | 558 | yield dbus_client.unsubscribe_share(sid) | ||
1586 | 559 | except dbus_client.VolumesError, e: | ||
1587 | 560 | self.assertEqual(e[0], sid) | ||
1588 | 561 | else: | ||
1589 | 562 | self.fail('dbus_client.unsubscribe_share should be errbacking') | ||
1590 | 563 | |||
1591 | 564 | |||
1592 | 413 | class StatusMockDBusSyncDaemon(dbus.service.Object): | 565 | class StatusMockDBusSyncDaemon(dbus.service.Object): |
1593 | 414 | """A mock object that mimicks syncdaemon regarding the Status iface.""" | 566 | """A mock object that mimicks syncdaemon regarding the Status iface.""" |
1594 | 415 | 567 | ||
1595 | @@ -549,6 +701,8 @@ | |||
1596 | 549 | """A mock object that mimicks syncdaemon.""" | 701 | """A mock object that mimicks syncdaemon.""" |
1597 | 550 | 702 | ||
1598 | 551 | ROOT_DIR = u'/yadda/yoda/Test me' | 703 | ROOT_DIR = u'/yadda/yoda/Test me' |
1599 | 704 | SHARES_DIR = u'/yadda/yoda/.hidden/ugly/dir/name/shares' | ||
1600 | 705 | SHARES_DIR_LINK = u'/yadda/yoda/Test me/Shared With Me' | ||
1601 | 552 | 706 | ||
1602 | 553 | @dbus.service.method(sd_dbus_iface.DBUS_IFACE_SYNC_NAME, | 707 | @dbus.service.method(sd_dbus_iface.DBUS_IFACE_SYNC_NAME, |
1603 | 554 | in_signature='', out_signature='s') | 708 | in_signature='', out_signature='s') |
1604 | @@ -556,6 +710,18 @@ | |||
1605 | 556 | """Return the root dir/mount point.""" | 710 | """Return the root dir/mount point.""" |
1606 | 557 | return self.ROOT_DIR | 711 | return self.ROOT_DIR |
1607 | 558 | 712 | ||
1608 | 713 | @dbus.service.method(sd_dbus_iface.DBUS_IFACE_SYNC_NAME, | ||
1609 | 714 | in_signature='', out_signature='s') | ||
1610 | 715 | def get_sharesdir(self): | ||
1611 | 716 | """Return the shares dir/mount point.""" | ||
1612 | 717 | return self.SHARES_DIR | ||
1613 | 718 | |||
1614 | 719 | @dbus.service.method(sd_dbus_iface.DBUS_IFACE_SYNC_NAME, | ||
1615 | 720 | in_signature='', out_signature='s') | ||
1616 | 721 | def get_sharesdir_link(self): | ||
1617 | 722 | """Return the root dir/mount point.""" | ||
1618 | 723 | return self.SHARES_DIR_LINK | ||
1619 | 724 | |||
1620 | 559 | 725 | ||
1621 | 560 | class BasicTestCase(DBusClientTestCase): | 726 | class BasicTestCase(DBusClientTestCase): |
1622 | 561 | """Test for the basic dbus client methods.""" | 727 | """Test for the basic dbus client methods.""" |
1623 | @@ -571,3 +737,17 @@ | |||
1624 | 571 | root = yield dbus_client.get_root_dir() | 737 | root = yield dbus_client.get_root_dir() |
1625 | 572 | 738 | ||
1626 | 573 | self.assertEqual(MockDBusSyncDaemon.ROOT_DIR, root) | 739 | self.assertEqual(MockDBusSyncDaemon.ROOT_DIR, root) |
1627 | 740 | |||
1628 | 741 | @inlineCallbacks | ||
1629 | 742 | def test_get_shares_dir(self): | ||
1630 | 743 | """Retrieve current syncdaemon shares dir.""" | ||
1631 | 744 | result = yield dbus_client.get_shares_dir() | ||
1632 | 745 | |||
1633 | 746 | self.assertEqual(MockDBusSyncDaemon.SHARES_DIR, result) | ||
1634 | 747 | |||
1635 | 748 | @inlineCallbacks | ||
1636 | 749 | def test_get_shares_dir_link(self): | ||
1637 | 750 | """Retrieve current syncdaemon shares dir.""" | ||
1638 | 751 | result = yield dbus_client.get_shares_dir_link() | ||
1639 | 752 | |||
1640 | 753 | self.assertEqual(MockDBusSyncDaemon.SHARES_DIR_LINK, result) | ||
1641 | 574 | 754 | ||
1642 | === modified file 'ubuntuone/controlpanel/tests/__init__.py' | |||
1643 | --- ubuntuone/controlpanel/tests/__init__.py 2011-01-25 19:08:59 +0000 | |||
1644 | +++ ubuntuone/controlpanel/tests/__init__.py 2011-02-12 03:22:55 +0000 | |||
1645 | @@ -161,8 +161,14 @@ | |||
1646 | 161 | u'volume_id': u'1deb2874-3d28-46ae-9999-d5f48de9f460'}, | 161 | u'volume_id': u'1deb2874-3d28-46ae-9999-d5f48de9f460'}, |
1647 | 162 | ] | 162 | ] |
1648 | 163 | 163 | ||
1649 | 164 | ROOT_PATH = u'/home/tester/Ubuntu One' | ||
1650 | 165 | SHARES_PATH = u'/home/tester/.local/share/ubuntuone/shares' | ||
1651 | 166 | SHARES_PATH_LINK = ROOT_PATH + u'/Shared With Me' | ||
1652 | 167 | |||
1653 | 164 | SAMPLE_SHARES = [ | 168 | SAMPLE_SHARES = [ |
1654 | 169 | |||
1655 | 165 | {u'accepted': u'True', | 170 | {u'accepted': u'True', |
1656 | 171 | u'subscribed': u'True', | ||
1657 | 166 | u'access_level': u'View', | 172 | u'access_level': u'View', |
1658 | 167 | u'free_bytes': u'39892622746', | 173 | u'free_bytes': u'39892622746', |
1659 | 168 | u'generation': u'2704', | 174 | u'generation': u'2704', |
1660 | @@ -170,11 +176,12 @@ | |||
1661 | 170 | u'node_id': u'c483f419-ed28-490a-825d-a8c074e2d795', | 176 | u'node_id': u'c483f419-ed28-490a-825d-a8c074e2d795', |
1662 | 171 | u'other_username': u'otheruser', | 177 | u'other_username': u'otheruser', |
1663 | 172 | u'other_visible_name': u'Other User', | 178 | u'other_visible_name': u'Other User', |
1665 | 173 | u'path': u'/home/tester/.local/share/ubuntuone/shares/re from Other User', | 179 | u'path': SHARES_PATH + u'/re from Other User', |
1666 | 174 | u'type': u'Share', | 180 | u'type': u'Share', |
1667 | 175 | u'volume_id': u'4a1b263b-a2b3-4f66-9e66-4cd18050810d'}, | 181 | u'volume_id': u'4a1b263b-a2b3-4f66-9e66-4cd18050810d'}, |
1668 | 176 | 182 | ||
1669 | 177 | {u'accepted': u'True', | 183 | {u'accepted': u'True', |
1670 | 184 | u'subscribed': u'True', | ||
1671 | 178 | u'access_level': u'Modify', | 185 | u'access_level': u'Modify', |
1672 | 179 | u'free_bytes': u'39892622746', | 186 | u'free_bytes': u'39892622746', |
1673 | 180 | u'generation': u'2704', | 187 | u'generation': u'2704', |
1674 | @@ -182,9 +189,78 @@ | |||
1675 | 182 | u'node_id': u'84544ea4-aefe-4f91-9bb9-ed7b0a805baf', | 189 | u'node_id': u'84544ea4-aefe-4f91-9bb9-ed7b0a805baf', |
1676 | 183 | u'other_username': u'otheruser', | 190 | u'other_username': u'otheruser', |
1677 | 184 | u'other_visible_name': u'Other User', | 191 | u'other_visible_name': u'Other User', |
1679 | 185 | u'path': u'/home/tester/.local/share/ubuntuone/shares/do from Other User', | 192 | u'path': SHARES_PATH + u'/do from Other User', |
1680 | 186 | u'type': u'Share', | 193 | u'type': u'Share', |
1681 | 187 | u'volume_id': u'7d130dfe-98b2-4bd5-8708-9eeba9838ac0'}, | 194 | u'volume_id': u'7d130dfe-98b2-4bd5-8708-9eeba9838ac0'}, |
1682 | 195 | |||
1683 | 196 | {u'name': u'yadda', | ||
1684 | 197 | u'subscribed': u'True', | ||
1685 | 198 | u'generation': u'36', | ||
1686 | 199 | u'other_username': u'https://login.ubuntu.com/+id/nHRnYmz', | ||
1687 | 200 | u'other_visible_name': u'', | ||
1688 | 201 | u'access_level': u'View', | ||
1689 | 202 | u'node_id': u'ca3a1cec-09d2-485e-9685-1a5180bd6441', | ||
1690 | 203 | u'volume_id': u'f1f1741f-ba49-46ef-b682-816c97e6e3d6', | ||
1691 | 204 | u'free_bytes': u'2146703403', | ||
1692 | 205 | u'path': SHARES_PATH + u'/yadda from ', | ||
1693 | 206 | u'accepted': u'True', | ||
1694 | 207 | u'type': u'Share'}, | ||
1695 | 208 | |||
1696 | 209 | {u'name': u'images', | ||
1697 | 210 | u'subscribed': u'True', | ||
1698 | 211 | u'generation': u'36', | ||
1699 | 212 | u'other_username': | ||
1700 | 213 | u'https://login.ubuntu.com/+id/nHRnYmz', | ||
1701 | 214 | u'other_visible_name': u'', | ||
1702 | 215 | u'access_level': u'Modify', | ||
1703 | 216 | u'node_id': | ||
1704 | 217 | u'b932f0d3-6998-423f-9225-7683a4adbd6f', | ||
1705 | 218 | u'volume_id': | ||
1706 | 219 | u'a73f889d-ffd3-4447-b351-f0d8130d1e1a', | ||
1707 | 220 | u'free_bytes': u'2146703403', | ||
1708 | 221 | u'path': SHARES_PATH + u'/images from ', | ||
1709 | 222 | u'accepted': u'True', | ||
1710 | 223 | u'type': u'Share'}, | ||
1711 | 224 | |||
1712 | 225 | {u'name': u'read-only', | ||
1713 | 226 | u'subscribed': u'True', | ||
1714 | 227 | u'generation': u'315', | ||
1715 | 228 | u'other_username': u'sharing-user', | ||
1716 | 229 | u'other_visible_name': u'A Sharing User', | ||
1717 | 230 | u'access_level': u'View', | ||
1718 | 231 | u'node_id': u'fd944823-e4c2-45a4-8c95-05997698bdbc', | ||
1719 | 232 | u'volume_id': | ||
1720 | 233 | u'64b43c96-6c7c-4135-994f-03a1a3774512', | ||
1721 | 234 | u'free_bytes': u'108786811673', | ||
1722 | 235 | u'path': SHARES_PATH + u'/read-only from A Sharing User', | ||
1723 | 236 | u'accepted': u'True', | ||
1724 | 237 | u'type': u'Share'}, | ||
1725 | 238 | |||
1726 | 239 | {u'name': u'read-write', | ||
1727 | 240 | u'subscribed': u'True', | ||
1728 | 241 | u'generation': u'314', | ||
1729 | 242 | u'other_username': u'sharing-user', | ||
1730 | 243 | u'other_visible_name': u'A Sharing User', | ||
1731 | 244 | u'access_level': u'Modify', | ||
1732 | 245 | u'node_id': u'e95662f7-9979-4745-8c21-8edaf893f143', | ||
1733 | 246 | u'volume_id': u'8896e8f8-57a3-4bf9-8558-fc54b7a3a777', | ||
1734 | 247 | u'free_bytes': u'108786811673', | ||
1735 | 248 | u'path': SHARES_PATH + u'/read-write from A Sharing User', | ||
1736 | 249 | u'accepted': u'True', | ||
1737 | 250 | u'type': u'Share'}, | ||
1738 | 251 | |||
1739 | 252 | {u'accepted': u'', | ||
1740 | 253 | u'access_level': u'View', | ||
1741 | 254 | u'free_bytes': u'', | ||
1742 | 255 | u'generation': u'', | ||
1743 | 256 | u'name': u'unaccepted', | ||
1744 | 257 | u'node_id': u'67b61c92-855c-49d8-8e09-6d201d15c999', | ||
1745 | 258 | u'other_username': u'bad guy', | ||
1746 | 259 | u'other_visible_name': u'', | ||
1747 | 260 | u'path': SHARES_PATH + u'/unaccepted from ', | ||
1748 | 261 | u'subscribed': u'', | ||
1749 | 262 | u'type': u'Share', | ||
1750 | 263 | u'volume_id': u'19963c95-c684-48db-8668-ebe6d820d5c3'}, | ||
1751 | 188 | ] | 264 | ] |
1752 | 189 | 265 | ||
1753 | 190 | SAMPLE_SHARED = [ | 266 | SAMPLE_SHARED = [ |
1754 | @@ -196,7 +272,7 @@ | |||
1755 | 196 | u'node_id': u'31e47530-9448-4f03-b4dc-4154fdf35225', | 272 | u'node_id': u'31e47530-9448-4f03-b4dc-4154fdf35225', |
1756 | 197 | u'other_username': u'otheruser', | 273 | u'other_username': u'otheruser', |
1757 | 198 | u'other_visible_name': u'Other User', | 274 | u'other_visible_name': u'Other User', |
1759 | 199 | u'path': u'/home/tester/Ubuntu One/bar', | 275 | u'path': ROOT_PATH + u'/bar', |
1760 | 200 | u'type': u'Shared', | 276 | u'type': u'Shared', |
1761 | 201 | u'volume_id': u'79584900-517f-4dff-b2f3-20e8c1e79365'}, | 277 | u'volume_id': u'79584900-517f-4dff-b2f3-20e8c1e79365'}, |
1762 | 202 | ] | 278 | ] |
1763 | 203 | 279 | ||
1764 | === modified file 'ubuntuone/controlpanel/tests/test_backend.py' | |||
1765 | --- ubuntuone/controlpanel/tests/test_backend.py 2011-01-25 19:08:59 +0000 | |||
1766 | +++ ubuntuone/controlpanel/tests/test_backend.py 2011-02-12 03:22:55 +0000 | |||
1767 | @@ -19,6 +19,8 @@ | |||
1768 | 19 | 19 | ||
1769 | 20 | """Tests for the control panel backend.""" | 20 | """Tests for the control panel backend.""" |
1770 | 21 | 21 | ||
1771 | 22 | from collections import defaultdict | ||
1772 | 23 | |||
1773 | 22 | import simplejson | 24 | import simplejson |
1774 | 23 | 25 | ||
1775 | 24 | from twisted.internet import defer | 26 | from twisted.internet import defer |
1776 | @@ -42,6 +44,7 @@ | |||
1777 | 42 | EXPECTED_ACCOUNT_INFO, | 44 | EXPECTED_ACCOUNT_INFO, |
1778 | 43 | EXPECTED_ACCOUNT_INFO_WITH_CURRENT_PLAN, | 45 | EXPECTED_ACCOUNT_INFO_WITH_CURRENT_PLAN, |
1779 | 44 | EXPECTED_DEVICES_INFO, | 46 | EXPECTED_DEVICES_INFO, |
1780 | 47 | ROOT_PATH, | ||
1781 | 45 | SAMPLE_ACCOUNT_NO_CURRENT_PLAN, | 48 | SAMPLE_ACCOUNT_NO_CURRENT_PLAN, |
1782 | 46 | SAMPLE_ACCOUNT_WITH_CURRENT_PLAN, | 49 | SAMPLE_ACCOUNT_WITH_CURRENT_PLAN, |
1783 | 47 | SAMPLE_DEVICES_JSON, | 50 | SAMPLE_DEVICES_JSON, |
1784 | @@ -49,6 +52,8 @@ | |||
1785 | 49 | SAMPLE_QUOTA_JSON, | 52 | SAMPLE_QUOTA_JSON, |
1786 | 50 | SAMPLE_SHARED, | 53 | SAMPLE_SHARED, |
1787 | 51 | SAMPLE_SHARES, | 54 | SAMPLE_SHARES, |
1788 | 55 | SHARES_PATH, | ||
1789 | 56 | SHARES_PATH_LINK, | ||
1790 | 52 | TOKEN, | 57 | TOKEN, |
1791 | 53 | ) | 58 | ) |
1792 | 54 | from ubuntuone.controlpanel.webclient import WebClientError | 59 | from ubuntuone.controlpanel.webclient import WebClientError |
1793 | @@ -86,8 +91,8 @@ | |||
1794 | 86 | } | 91 | } |
1795 | 87 | status_changed_handler = None | 92 | status_changed_handler = None |
1796 | 88 | subscribed_folders = [] | 93 | subscribed_folders = [] |
1797 | 94 | subscribed_shares = [] | ||
1798 | 89 | actions = [] | 95 | actions = [] |
1799 | 90 | root_dir = u'/home/tester/Something/Pepe Mosquito' | ||
1800 | 91 | 96 | ||
1801 | 92 | def get_credentials(self): | 97 | def get_credentials(self): |
1802 | 93 | """Return the mock credentials.""" | 98 | """Return the mock credentials.""" |
1803 | @@ -145,7 +150,15 @@ | |||
1804 | 145 | 150 | ||
1805 | 146 | def get_root_dir(self): | 151 | def get_root_dir(self): |
1806 | 147 | """Grab the root dir.""" | 152 | """Grab the root dir.""" |
1808 | 148 | return self.root_dir | 153 | return ROOT_PATH |
1809 | 154 | |||
1810 | 155 | def get_shares_dir(self): | ||
1811 | 156 | """Grab the shares dir.""" | ||
1812 | 157 | return SHARES_PATH | ||
1813 | 158 | |||
1814 | 159 | def get_shares_dir_link(self): | ||
1815 | 160 | """Grab the shares dir.""" | ||
1816 | 161 | return SHARES_PATH_LINK | ||
1817 | 149 | 162 | ||
1818 | 150 | def get_folders(self): | 163 | def get_folders(self): |
1819 | 151 | """Grab list of folders.""" | 164 | """Grab list of folders.""" |
1820 | @@ -153,11 +166,23 @@ | |||
1821 | 153 | 166 | ||
1822 | 154 | def subscribe_folder(self, volume_id): | 167 | def subscribe_folder(self, volume_id): |
1823 | 155 | """Subcribe to 'volume_id'.""" | 168 | """Subcribe to 'volume_id'.""" |
1825 | 156 | self.subscribed_folders.append(volume_id) | 169 | MockDBusClient.subscribed_folders.append(volume_id) |
1826 | 157 | 170 | ||
1827 | 158 | def unsubscribe_folder(self, volume_id): | 171 | def unsubscribe_folder(self, volume_id): |
1828 | 159 | """Unsubcribe from 'volume_id'.""" | 172 | """Unsubcribe from 'volume_id'.""" |
1830 | 160 | self.subscribed_folders.remove(volume_id) | 173 | MockDBusClient.subscribed_folders.remove(volume_id) |
1831 | 174 | |||
1832 | 175 | def get_shares(self): | ||
1833 | 176 | """Grab list of shares.""" | ||
1834 | 177 | return SAMPLE_SHARES | ||
1835 | 178 | |||
1836 | 179 | def subscribe_share(self, volume_id): | ||
1837 | 180 | """Subcribe to 'volume_id'.""" | ||
1838 | 181 | MockDBusClient.subscribed_shares.append(volume_id) | ||
1839 | 182 | |||
1840 | 183 | def unsubscribe_share(self, volume_id): | ||
1841 | 184 | """Unsubcribe from 'volume_id'.""" | ||
1842 | 185 | MockDBusClient.subscribed_shares.remove(volume_id) | ||
1843 | 161 | 186 | ||
1844 | 162 | def get_current_status(self): | 187 | def get_current_status(self): |
1845 | 163 | """Grab syncdaemon status.""" | 188 | """Grab syncdaemon status.""" |
1846 | @@ -167,10 +192,6 @@ | |||
1847 | 167 | """Connect a handler for tracking syncdaemon status changes.""" | 192 | """Connect a handler for tracking syncdaemon status changes.""" |
1848 | 168 | self.status_changed_handler = handler | 193 | self.status_changed_handler = handler |
1849 | 169 | 194 | ||
1850 | 170 | def get_shares(self): | ||
1851 | 171 | """Grab list of shares (shares from others to the user).""" | ||
1852 | 172 | return SAMPLE_SHARES | ||
1853 | 173 | |||
1854 | 174 | def get_shared(self): | 195 | def get_shared(self): |
1855 | 175 | """Grab list of shared (shares from the user to others).""" | 196 | """Grab list of shared (shares from the user to others).""" |
1856 | 176 | return SAMPLE_SHARED | 197 | return SAMPLE_SHARED |
1857 | @@ -370,40 +391,106 @@ | |||
1858 | 370 | class BackendVolumesTestCase(BackendBasicTestCase): | 391 | class BackendVolumesTestCase(BackendBasicTestCase): |
1859 | 371 | """Volumes tests for the backend.""" | 392 | """Volumes tests for the backend.""" |
1860 | 372 | 393 | ||
1861 | 394 | def setUp(self): | ||
1862 | 395 | super(BackendVolumesTestCase, self).setUp() | ||
1863 | 396 | # fake quota info and calculate free bytes | ||
1864 | 397 | # pylint: disable=E1101 | ||
1865 | 398 | self.be.wc.results[ACCOUNT_API] = SAMPLE_ACCOUNT_NO_CURRENT_PLAN | ||
1866 | 399 | self.be.wc.results[QUOTA_API] = SAMPLE_QUOTA_JSON | ||
1867 | 400 | |||
1868 | 373 | @inlineCallbacks | 401 | @inlineCallbacks |
1869 | 374 | def test_volumes_info(self): | 402 | def test_volumes_info(self): |
1870 | 375 | """The volumes_info method exercises its callback.""" | 403 | """The volumes_info method exercises its callback.""" |
1871 | 376 | # fake quota info and calculate free bytes | ||
1872 | 377 | # pylint: disable=E1101 | ||
1873 | 378 | self.be.wc.results[ACCOUNT_API] = SAMPLE_ACCOUNT_NO_CURRENT_PLAN | ||
1874 | 379 | self.be.wc.results[QUOTA_API] = SAMPLE_QUOTA_JSON | ||
1875 | 380 | result = yield self.be.account_info() | 404 | result = yield self.be.account_info() |
1876 | 381 | free_bytes = int(result['quota_total']) - int(result['quota_used']) | 405 | free_bytes = int(result['quota_total']) - int(result['quota_used']) |
1877 | 382 | 406 | ||
1878 | 383 | # get root dir info | 407 | # get root dir info |
1882 | 384 | root_dir = MockDBusClient.root_dir | 408 | root_volume = {u'volume_id': u'', u'path': ROOT_PATH, |
1883 | 385 | root_volume = {u'volume_id': u'', u'path': root_dir, | 409 | u'subscribed': 'True', u'type': self.be.ROOT_TYPE} |
1884 | 386 | u'subscribed': 'True', u'type': u'ROOT'} | 410 | |
1885 | 411 | # get shares and group by sharing user | ||
1886 | 412 | shares = defaultdict(list) | ||
1887 | 413 | for share in SAMPLE_SHARES: | ||
1888 | 414 | # filter out non accepted values | ||
1889 | 415 | if not bool(share['accepted']): | ||
1890 | 416 | continue | ||
1891 | 417 | |||
1892 | 418 | share = share.copy() | ||
1893 | 419 | |||
1894 | 420 | nicer_path = share[u'path'].replace(SHARES_PATH, SHARES_PATH_LINK) | ||
1895 | 421 | share[u'path'] = nicer_path | ||
1896 | 422 | share[u'type'] = self.be.SHARE_TYPE | ||
1897 | 423 | |||
1898 | 424 | username = share['other_visible_name'] | ||
1899 | 425 | if not username: | ||
1900 | 426 | username = share['other_username'] + \ | ||
1901 | 427 | ' (%s)' % self.be.NAME_NOT_SET | ||
1902 | 428 | |||
1903 | 429 | shares[username].append(share) | ||
1904 | 430 | |||
1905 | 431 | folders = [] | ||
1906 | 432 | for folder in SAMPLE_FOLDERS: | ||
1907 | 433 | folder = folder.copy() | ||
1908 | 434 | folder[u'type'] = self.be.FOLDER_TYPE | ||
1909 | 435 | folders.append(folder) | ||
1910 | 436 | |||
1911 | 437 | expected = [(u'', unicode(free_bytes), [root_volume] + folders)] | ||
1912 | 438 | for other_user, data in shares.iteritems(): | ||
1913 | 439 | expected.append((other_user, data[0][u'free_bytes'], data)) | ||
1914 | 387 | 440 | ||
1915 | 388 | result = yield self.be.volumes_info() | 441 | result = yield self.be.volumes_info() |
1916 | 389 | |||
1917 | 390 | expected = [('', unicode(free_bytes), [root_volume] + SAMPLE_FOLDERS)] | ||
1918 | 391 | # later, we should unify folders and shares info | ||
1919 | 392 | self.assertEqual(result, expected) | 442 | self.assertEqual(result, expected) |
1920 | 393 | 443 | ||
1923 | 394 | @inlineCallbacks | 444 | # pylint: disable=W0212 |
1924 | 395 | def test_subscribe_volume(self): | 445 | |
1925 | 446 | def test_cached_volumes_are_initially_empty(self): | ||
1926 | 447 | """The cached volume list is empty.""" | ||
1927 | 448 | self.assertEqual(self.be._volumes, {}) | ||
1928 | 449 | |||
1929 | 450 | @inlineCallbacks | ||
1930 | 451 | def test_volumes_are_cached(self): | ||
1931 | 452 | """The volume list is cached.""" | ||
1932 | 453 | # get root dir info | ||
1933 | 454 | root_volume = {u'volume_id': u'', u'path': ROOT_PATH, | ||
1934 | 455 | u'subscribed': 'True', u'type': self.be.ROOT_TYPE} | ||
1935 | 456 | expected = {u'': root_volume} | ||
1936 | 457 | for volume in SAMPLE_SHARES + SAMPLE_FOLDERS: | ||
1937 | 458 | if volume[u'type'] == u'UDF': | ||
1938 | 459 | volume[u'type'] = self.be.FOLDER_TYPE | ||
1939 | 460 | else: | ||
1940 | 461 | volume[u'type'] = self.be.SHARE_TYPE | ||
1941 | 462 | |||
1942 | 463 | sid = volume['volume_id'] | ||
1943 | 464 | assert sid not in expected | ||
1944 | 465 | expected[sid] = volume | ||
1945 | 466 | |||
1946 | 467 | _ = yield self.be.volumes_info() | ||
1947 | 468 | |||
1948 | 469 | self.assertEqual(self.be._volumes, expected) | ||
1949 | 470 | |||
1950 | 471 | @inlineCallbacks | ||
1951 | 472 | def test_cached_volumes_are_updated_with_volume_info(self): | ||
1952 | 473 | """The cached volume list is updated.""" | ||
1953 | 474 | yield self.test_volumes_are_cached() | ||
1954 | 475 | yield self.test_volumes_are_cached() | ||
1955 | 476 | |||
1956 | 477 | @inlineCallbacks | ||
1957 | 478 | def test_subscribe_volume_folder(self): | ||
1958 | 396 | """The subscribe_volume method subscribes a folder.""" | 479 | """The subscribe_volume method subscribes a folder.""" |
1959 | 397 | fid = '0123-4567' | 480 | fid = '0123-4567' |
1960 | 481 | self.be._volumes[fid] = {u'type': self.be.FOLDER_TYPE} | ||
1961 | 482 | |||
1962 | 398 | yield self.be.subscribe_volume(volume_id=fid) | 483 | yield self.be.subscribe_volume(volume_id=fid) |
1963 | 399 | self.addCleanup(lambda: MockDBusClient.subscribed_folders.remove(fid)) | 484 | self.addCleanup(lambda: MockDBusClient.subscribed_folders.remove(fid)) |
1964 | 400 | 485 | ||
1965 | 401 | self.assertEqual(MockDBusClient.subscribed_folders, [fid]) | 486 | self.assertEqual(MockDBusClient.subscribed_folders, [fid]) |
1966 | 402 | 487 | ||
1967 | 403 | @inlineCallbacks | 488 | @inlineCallbacks |
1969 | 404 | def test_unsubscribe_volume(self): | 489 | def test_unsubscribe_volume_folder(self): |
1970 | 405 | """The unsubscribe_volume method unsubscribes a folder.""" | 490 | """The unsubscribe_volume method unsubscribes a folder.""" |
1971 | 406 | fid = '0123-4567' | 491 | fid = '0123-4567' |
1972 | 492 | self.be._volumes[fid] = {u'type': self.be.FOLDER_TYPE} | ||
1973 | 493 | |||
1974 | 407 | yield self.be.subscribe_volume(volume_id=fid) | 494 | yield self.be.subscribe_volume(volume_id=fid) |
1975 | 408 | self.assertEqual(MockDBusClient.subscribed_folders, [fid]) | 495 | self.assertEqual(MockDBusClient.subscribed_folders, [fid]) |
1976 | 409 | 496 | ||
1977 | @@ -412,9 +499,34 @@ | |||
1978 | 412 | self.assertEqual(MockDBusClient.subscribed_folders, []) | 499 | self.assertEqual(MockDBusClient.subscribed_folders, []) |
1979 | 413 | 500 | ||
1980 | 414 | @inlineCallbacks | 501 | @inlineCallbacks |
1982 | 415 | def test_change_volume_settings(self): | 502 | def test_subscribe_volume_share(self): |
1983 | 503 | """The subscribe_volume method subscribes a share.""" | ||
1984 | 504 | sid = '0123-4567' | ||
1985 | 505 | self.be._volumes[sid] = {u'type': self.be.SHARE_TYPE} | ||
1986 | 506 | |||
1987 | 507 | yield self.be.subscribe_volume(volume_id=sid) | ||
1988 | 508 | self.addCleanup(lambda: MockDBusClient.subscribed_shares.remove(sid)) | ||
1989 | 509 | |||
1990 | 510 | self.assertEqual(MockDBusClient.subscribed_shares, [sid]) | ||
1991 | 511 | |||
1992 | 512 | @inlineCallbacks | ||
1993 | 513 | def test_unsubscribe_volume_share(self): | ||
1994 | 514 | """The unsubscribe_volume method unsubscribes a share.""" | ||
1995 | 515 | sid = '0123-4567' | ||
1996 | 516 | self.be._volumes[sid] = {u'type': self.be.SHARE_TYPE} | ||
1997 | 517 | |||
1998 | 518 | yield self.be.subscribe_volume(volume_id=sid) | ||
1999 | 519 | self.assertEqual(MockDBusClient.subscribed_shares, [sid]) | ||
2000 | 520 | |||
2001 | 521 | yield self.be.unsubscribe_volume(volume_id=sid) | ||
2002 | 522 | |||
2003 | 523 | self.assertEqual(MockDBusClient.subscribed_shares, []) | ||
2004 | 524 | |||
2005 | 525 | @inlineCallbacks | ||
2006 | 526 | def test_change_volume_settings_folder(self): | ||
2007 | 416 | """The volume settings can be changed.""" | 527 | """The volume settings can be changed.""" |
2008 | 417 | fid = '0123-4567' | 528 | fid = '0123-4567' |
2009 | 529 | self.be._volumes[fid] = {u'type': self.be.FOLDER_TYPE} | ||
2010 | 418 | 530 | ||
2011 | 419 | yield self.be.change_volume_settings(fid, {'subscribed': 'True'}) | 531 | yield self.be.change_volume_settings(fid, {'subscribed': 'True'}) |
2012 | 420 | self.assertEqual(MockDBusClient.subscribed_folders, [fid]) | 532 | self.assertEqual(MockDBusClient.subscribed_folders, [fid]) |
2013 | @@ -423,10 +535,23 @@ | |||
2014 | 423 | self.assertEqual(MockDBusClient.subscribed_folders, []) | 535 | self.assertEqual(MockDBusClient.subscribed_folders, []) |
2015 | 424 | 536 | ||
2016 | 425 | @inlineCallbacks | 537 | @inlineCallbacks |
2017 | 538 | def test_change_volume_settings_share(self): | ||
2018 | 539 | """The volume settings can be changed.""" | ||
2019 | 540 | sid = '0123-4567' | ||
2020 | 541 | self.be._volumes[sid] = {u'type': self.be.SHARE_TYPE} | ||
2021 | 542 | |||
2022 | 543 | yield self.be.change_volume_settings(sid, {'subscribed': 'True'}) | ||
2023 | 544 | self.assertEqual(MockDBusClient.subscribed_shares, [sid]) | ||
2024 | 545 | |||
2025 | 546 | yield self.be.change_volume_settings(sid, {'subscribed': ''}) | ||
2026 | 547 | self.assertEqual(MockDBusClient.subscribed_shares, []) | ||
2027 | 548 | |||
2028 | 549 | @inlineCallbacks | ||
2029 | 426 | def test_change_volume_settings_no_setting(self): | 550 | def test_change_volume_settings_no_setting(self): |
2030 | 427 | """The change volume settings does not fail on empty settings.""" | 551 | """The change volume settings does not fail on empty settings.""" |
2031 | 428 | yield self.be.change_volume_settings('test', {}) | 552 | yield self.be.change_volume_settings('test', {}) |
2032 | 429 | self.assertEqual(MockDBusClient.subscribed_folders, []) | 553 | self.assertEqual(MockDBusClient.subscribed_folders, []) |
2033 | 554 | self.assertEqual(MockDBusClient.subscribed_shares, []) | ||
2034 | 430 | 555 | ||
2035 | 431 | 556 | ||
2036 | 432 | class BackendSyncStatusTestCase(BackendBasicTestCase): | 557 | class BackendSyncStatusTestCase(BackendBasicTestCase): |
Looks good