Merge lp:~dobey/ubuntuone-control-panel/update-4-0 into lp:ubuntuone-control-panel/stable-4-0
- update-4-0
- Merge into stable-4-0
Status: | Merged |
---|---|
Approved by: | Alejandro J. Cura |
Approved revision: | no longer in the source branch. |
Merged at revision: | 337 |
Proposed branch: | lp:~dobey/ubuntuone-control-panel/update-4-0 |
Merge into: | lp:ubuntuone-control-panel/stable-4-0 |
Diff against target: |
2170 lines (+1686/-51) 23 files modified
data/qt/controlpanel.ui (+1/-1) data/qt/images.qrc (+1/-0) data/qt/share_file.ui (+94/-0) data/qt/share_links.ui (+196/-10) data/qt/ubuntuone.qss (+65/-0) ubuntuone/controlpanel/backend.py (+36/-1) ubuntuone/controlpanel/gui/__init__.py (+2/-0) ubuntuone/controlpanel/gui/qt/addfolder.py (+3/-3) ubuntuone/controlpanel/gui/qt/main/__init__.py (+2/-0) ubuntuone/controlpanel/gui/qt/main/tests/test_main.py (+20/-2) ubuntuone/controlpanel/gui/qt/preferences.py (+4/-2) ubuntuone/controlpanel/gui/qt/share_file.py (+63/-0) ubuntuone/controlpanel/gui/qt/share_links.py (+189/-1) ubuntuone/controlpanel/gui/qt/share_links_search.py (+318/-0) ubuntuone/controlpanel/gui/qt/tests/__init__.py (+18/-0) ubuntuone/controlpanel/gui/qt/tests/test_preferences.py (+8/-2) ubuntuone/controlpanel/gui/qt/tests/test_share_file.py (+76/-0) ubuntuone/controlpanel/gui/qt/tests/test_share_links.py (+161/-3) ubuntuone/controlpanel/gui/qt/tests/test_share_links_search.py (+302/-0) ubuntuone/controlpanel/gui/qt/tests/test_systray.py (+15/-26) ubuntuone/controlpanel/sd_client/__init__.py (+20/-0) ubuntuone/controlpanel/tests/test_backend.py (+64/-0) ubuntuone/controlpanel/tests/test_sd_client.py (+28/-0) |
To merge this branch: | bzr merge lp:~dobey/ubuntuone-control-panel/update-4-0 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alejandro J. Cura (community) | trivial | Approve | |
Review via email: mp+121914@code.launchpad.net |
Commit message
[Diego Sarmentero]
- Adding functionality to the Share Links Tab (LP: #1039142).
[Roberto Alsina]
- Fixed saving/restoring the speed throttling (Fixes LP:1040899)
- Switched to non-native dialog on darwin (LP:1040905).
- Fixed share/UDF list scrolling on Mac (LP:1018918)
[Manuel de la Peña]
- Fixed the tab aligment by asserting that tabs are on the left via the qss (LP: #1019224).
Description of the change
- 337. By Diego Sarmentero
-
[Diego Sarmentero]
- Adding functionality to the Share Links Tab (LP: #1039142).
[Roberto Alsina]
- Fixed saving/restoring the speed throttling (Fixes LP:1040899)
- Switched to non-native dialog on darwin (LP:1040905).
- Fixed share/UDF list scrolling on Mac (LP:1018918)[Manuel de la Peña]
- Fixed the tab aligment by asserting that tabs are on the left via the qss (LP: #1019224).
Preview Diff
1 | === added file 'data/delete_search.png' |
2 | Binary files data/delete_search.png 1970-01-01 00:00:00 +0000 and data/delete_search.png 2012-08-29 18:07:21 +0000 differ |
3 | === modified file 'data/qt/controlpanel.ui' |
4 | --- data/qt/controlpanel.ui 2012-08-20 20:17:35 +0000 |
5 | +++ data/qt/controlpanel.ui 2012-08-29 18:07:21 +0000 |
6 | @@ -229,7 +229,7 @@ |
7 | </sizepolicy> |
8 | </property> |
9 | <property name="currentIndex"> |
10 | - <number>1</number> |
11 | + <number>0</number> |
12 | </property> |
13 | <widget class="FoldersPanel" name="folders_tab"> |
14 | <attribute name="title"> |
15 | |
16 | === modified file 'data/qt/images.qrc' |
17 | --- data/qt/images.qrc 2012-05-29 14:30:36 +0000 |
18 | +++ data/qt/images.qrc 2012-08-29 18:07:21 +0000 |
19 | @@ -25,6 +25,7 @@ |
20 | <file>../sync_status_syncing.png</file> |
21 | <file>../twitter.png</file> |
22 | <file>../facebook.png</file> |
23 | + <file>../delete_search.png</file> |
24 | <file>../Ubuntu-R.ttf</file> |
25 | <file>../Ubuntu-B.ttf</file> |
26 | <file>ubuntuone.qss</file> |
27 | |
28 | === added file 'data/qt/share_file.ui' |
29 | --- data/qt/share_file.ui 1970-01-01 00:00:00 +0000 |
30 | +++ data/qt/share_file.ui 2012-08-29 18:07:21 +0000 |
31 | @@ -0,0 +1,94 @@ |
32 | +<?xml version="1.0" encoding="UTF-8"?> |
33 | +<ui version="4.0"> |
34 | + <class>Form</class> |
35 | + <widget class="QWidget" name="Form"> |
36 | + <property name="geometry"> |
37 | + <rect> |
38 | + <x>0</x> |
39 | + <y>0</y> |
40 | + <width>519</width> |
41 | + <height>58</height> |
42 | + </rect> |
43 | + </property> |
44 | + <property name="windowTitle"> |
45 | + <string>Form</string> |
46 | + </property> |
47 | + <layout class="QHBoxLayout" name="horizontalLayout"> |
48 | + <item> |
49 | + <layout class="QHBoxLayout" name="horizontalLayout_2"> |
50 | + <item> |
51 | + <widget class="QLabel" name="lbl_icon"> |
52 | + <property name="text"> |
53 | + <string/> |
54 | + </property> |
55 | + </widget> |
56 | + </item> |
57 | + <item> |
58 | + <layout class="QVBoxLayout" name="verticalLayout_3"> |
59 | + <item> |
60 | + <widget class="QLabel" name="lbl_filename"> |
61 | + <property name="text"> |
62 | + <string>filename</string> |
63 | + </property> |
64 | + </widget> |
65 | + </item> |
66 | + <item> |
67 | + <widget class="QLabel" name="lbl_path"> |
68 | + <property name="sizePolicy"> |
69 | + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> |
70 | + <horstretch>0</horstretch> |
71 | + <verstretch>0</verstretch> |
72 | + </sizepolicy> |
73 | + </property> |
74 | + <property name="font"> |
75 | + <font> |
76 | + <pointsize>9</pointsize> |
77 | + </font> |
78 | + </property> |
79 | + <property name="text"> |
80 | + <string>path</string> |
81 | + </property> |
82 | + </widget> |
83 | + </item> |
84 | + </layout> |
85 | + </item> |
86 | + </layout> |
87 | + </item> |
88 | + <item> |
89 | + <spacer name="horizontalSpacer"> |
90 | + <property name="orientation"> |
91 | + <enum>Qt::Horizontal</enum> |
92 | + </property> |
93 | + <property name="sizeHint" stdset="0"> |
94 | + <size> |
95 | + <width>40</width> |
96 | + <height>20</height> |
97 | + </size> |
98 | + </property> |
99 | + </spacer> |
100 | + </item> |
101 | + <item> |
102 | + <widget class="QPushButton" name="btn_open"> |
103 | + <property name="sizePolicy"> |
104 | + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> |
105 | + <horstretch>0</horstretch> |
106 | + <verstretch>0</verstretch> |
107 | + </sizepolicy> |
108 | + </property> |
109 | + <property name="text"> |
110 | + <string>Open</string> |
111 | + </property> |
112 | + </widget> |
113 | + </item> |
114 | + <item> |
115 | + <widget class="QPushButton" name="btn_disable"> |
116 | + <property name="text"> |
117 | + <string>Disable link</string> |
118 | + </property> |
119 | + </widget> |
120 | + </item> |
121 | + </layout> |
122 | + </widget> |
123 | + <resources/> |
124 | + <connections/> |
125 | +</ui> |
126 | |
127 | === modified file 'data/qt/share_links.ui' |
128 | --- data/qt/share_links.ui 2012-08-20 17:51:54 +0000 |
129 | +++ data/qt/share_links.ui 2012-08-29 18:07:21 +0000 |
130 | @@ -6,13 +6,16 @@ |
131 | <rect> |
132 | <x>0</x> |
133 | <y>0</y> |
134 | - <width>532</width> |
135 | - <height>335</height> |
136 | + <width>567</width> |
137 | + <height>341</height> |
138 | </rect> |
139 | </property> |
140 | <property name="windowTitle"> |
141 | <string>Form</string> |
142 | </property> |
143 | + <property name="styleSheet"> |
144 | + <string notr="true"/> |
145 | + </property> |
146 | <layout class="QVBoxLayout" name="verticalLayout"> |
147 | <property name="spacing"> |
148 | <number>15</number> |
149 | @@ -38,7 +41,7 @@ |
150 | <enum>QLayout::SetDefaultConstraint</enum> |
151 | </property> |
152 | <property name="leftMargin"> |
153 | - <number>10</number> |
154 | + <number>15</number> |
155 | </property> |
156 | <item> |
157 | <widget class="QLabel" name="search_files_lbl"> |
158 | @@ -61,7 +64,7 @@ |
159 | </widget> |
160 | </item> |
161 | <item> |
162 | - <widget class="QLineEdit" name="lineEdit"> |
163 | + <widget class="SearchBox" name="line_search"> |
164 | <property name="sizePolicy"> |
165 | <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> |
166 | <horstretch>0</horstretch> |
167 | @@ -82,7 +85,10 @@ |
168 | </layout> |
169 | </item> |
170 | <item> |
171 | - <widget class="QStackedWidget" name="stackedWidget"> |
172 | + <widget class="QStackedWidget" name="stacked_widget"> |
173 | + <property name="currentIndex"> |
174 | + <number>0</number> |
175 | + </property> |
176 | <widget class="QWidget" name="page"> |
177 | <layout class="QVBoxLayout" name="verticalLayout_4"> |
178 | <property name="spacing"> |
179 | @@ -107,13 +113,38 @@ |
180 | <number>0</number> |
181 | </property> |
182 | <item> |
183 | - <widget class="QTreeWidget" name="treeWidget"> |
184 | + <widget class="QTreeWidget" name="tree_shared_files"> |
185 | + <property name="alternatingRowColors"> |
186 | + <bool>true</bool> |
187 | + </property> |
188 | + <property name="indentation"> |
189 | + <number>15</number> |
190 | + </property> |
191 | + <property name="rootIsDecorated"> |
192 | + <bool>false</bool> |
193 | + </property> |
194 | <attribute name="headerVisible"> |
195 | <bool>false</bool> |
196 | </attribute> |
197 | - <column> |
198 | - <property name="text"> |
199 | - <string notr="true">1</string> |
200 | + <attribute name="headerDefaultSectionSize"> |
201 | + <number>250</number> |
202 | + </attribute> |
203 | + <attribute name="headerStretchLastSection"> |
204 | + <bool>true</bool> |
205 | + </attribute> |
206 | + <column> |
207 | + <property name="text"> |
208 | + <string notr="true">Filename</string> |
209 | + </property> |
210 | + </column> |
211 | + <column> |
212 | + <property name="text"> |
213 | + <string>Path</string> |
214 | + </property> |
215 | + </column> |
216 | + <column> |
217 | + <property name="text"> |
218 | + <string notr="true">Actions</string> |
219 | </property> |
220 | </column> |
221 | </widget> |
222 | @@ -123,11 +154,166 @@ |
223 | </item> |
224 | </layout> |
225 | </widget> |
226 | - <widget class="QWidget" name="page_2"/> |
227 | + <widget class="QWidget" name="page_2"> |
228 | + <layout class="QVBoxLayout" name="verticalLayout_5"> |
229 | + <property name="spacing"> |
230 | + <number>0</number> |
231 | + </property> |
232 | + <property name="margin"> |
233 | + <number>0</number> |
234 | + </property> |
235 | + <item> |
236 | + <layout class="QHBoxLayout" name="horizontalLayout"> |
237 | + <property name="spacing"> |
238 | + <number>0</number> |
239 | + </property> |
240 | + <property name="leftMargin"> |
241 | + <number>15</number> |
242 | + </property> |
243 | + <item> |
244 | + <widget class="QLabel" name="label_share_file"> |
245 | + <property name="sizePolicy"> |
246 | + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> |
247 | + <horstretch>0</horstretch> |
248 | + <verstretch>0</verstretch> |
249 | + </sizepolicy> |
250 | + </property> |
251 | + <property name="font"> |
252 | + <font> |
253 | + <weight>75</weight> |
254 | + <bold>true</bold> |
255 | + </font> |
256 | + </property> |
257 | + <property name="text"> |
258 | + <string>Share this file</string> |
259 | + </property> |
260 | + </widget> |
261 | + </item> |
262 | + <item> |
263 | + <spacer name="horizontalSpacer"> |
264 | + <property name="orientation"> |
265 | + <enum>Qt::Horizontal</enum> |
266 | + </property> |
267 | + <property name="sizeType"> |
268 | + <enum>QSizePolicy::Expanding</enum> |
269 | + </property> |
270 | + <property name="sizeHint" stdset="0"> |
271 | + <size> |
272 | + <width>40</width> |
273 | + <height>0</height> |
274 | + </size> |
275 | + </property> |
276 | + </spacer> |
277 | + </item> |
278 | + <item> |
279 | + <widget class="QPushButton" name="back_to_file_list"> |
280 | + <property name="text"> |
281 | + <string>Back to file list</string> |
282 | + </property> |
283 | + </widget> |
284 | + </item> |
285 | + </layout> |
286 | + </item> |
287 | + <item> |
288 | + <layout class="QVBoxLayout" name="verticalLayout"> |
289 | + <property name="spacing"> |
290 | + <number>0</number> |
291 | + </property> |
292 | + <item> |
293 | + <widget class="QFrame" name="frame_share_file"> |
294 | + <property name="frameShape"> |
295 | + <enum>QFrame::StyledPanel</enum> |
296 | + </property> |
297 | + <property name="frameShadow"> |
298 | + <enum>QFrame::Raised</enum> |
299 | + </property> |
300 | + <layout class="QVBoxLayout" name="verticalLayout_7"> |
301 | + <property name="spacing"> |
302 | + <number>0</number> |
303 | + </property> |
304 | + <property name="margin"> |
305 | + <number>0</number> |
306 | + </property> |
307 | + <item> |
308 | + <layout class="QHBoxLayout" name="hbox_share_file"> |
309 | + <property name="spacing"> |
310 | + <number>0</number> |
311 | + </property> |
312 | + </layout> |
313 | + </item> |
314 | + <item> |
315 | + <layout class="QVBoxLayout" name="verticalLayout_6"> |
316 | + <property name="leftMargin"> |
317 | + <number>15</number> |
318 | + </property> |
319 | + <property name="topMargin"> |
320 | + <number>15</number> |
321 | + </property> |
322 | + <item> |
323 | + <widget class="QLineEdit" name="line_copy_link"> |
324 | + <property name="sizePolicy"> |
325 | + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> |
326 | + <horstretch>0</horstretch> |
327 | + <verstretch>0</verstretch> |
328 | + </sizepolicy> |
329 | + </property> |
330 | + <property name="minimumSize"> |
331 | + <size> |
332 | + <width>470</width> |
333 | + <height>0</height> |
334 | + </size> |
335 | + </property> |
336 | + <property name="readOnly"> |
337 | + <bool>true</bool> |
338 | + </property> |
339 | + </widget> |
340 | + </item> |
341 | + <item> |
342 | + <widget class="QPushButton" name="open_in_browser"> |
343 | + <property name="sizePolicy"> |
344 | + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> |
345 | + <horstretch>0</horstretch> |
346 | + <verstretch>0</verstretch> |
347 | + </sizepolicy> |
348 | + </property> |
349 | + <property name="text"> |
350 | + <string>Open in browser</string> |
351 | + </property> |
352 | + </widget> |
353 | + </item> |
354 | + <item> |
355 | + <spacer name="verticalSpacer"> |
356 | + <property name="orientation"> |
357 | + <enum>Qt::Vertical</enum> |
358 | + </property> |
359 | + <property name="sizeHint" stdset="0"> |
360 | + <size> |
361 | + <width>0</width> |
362 | + <height>1</height> |
363 | + </size> |
364 | + </property> |
365 | + </spacer> |
366 | + </item> |
367 | + </layout> |
368 | + </item> |
369 | + </layout> |
370 | + </widget> |
371 | + </item> |
372 | + </layout> |
373 | + </item> |
374 | + </layout> |
375 | + </widget> |
376 | </widget> |
377 | </item> |
378 | </layout> |
379 | </widget> |
380 | + <customwidgets> |
381 | + <customwidget> |
382 | + <class>SearchBox</class> |
383 | + <extends>QLineEdit</extends> |
384 | + <header>ubuntuone.controlpanel.gui.qt.share_links_search</header> |
385 | + </customwidget> |
386 | + </customwidgets> |
387 | <resources/> |
388 | <connections/> |
389 | </ui> |
390 | |
391 | === modified file 'data/qt/ubuntuone.qss' |
392 | --- data/qt/ubuntuone.qss 2012-05-15 18:43:52 +0000 |
393 | +++ data/qt/ubuntuone.qss 2012-08-29 18:07:21 +0000 |
394 | @@ -19,6 +19,12 @@ |
395 | border-color: #333333; |
396 | } |
397 | |
398 | +QFrame#frame_share_file { |
399 | + border-top-style: solid; |
400 | + border-width: 1px; |
401 | + border-color: #727272; |
402 | +} |
403 | + |
404 | UbuntuOneWizard, |
405 | QFrame#frame_header { |
406 | background: white; |
407 | @@ -259,6 +265,10 @@ |
408 | text-decoration: underline; |
409 | } |
410 | |
411 | +QTabWidget::tab-bar { |
412 | + alignment: left; |
413 | +} |
414 | + |
415 | QGroupBox { |
416 | padding-top: 30px; |
417 | border: none; |
418 | @@ -312,6 +322,21 @@ |
419 | color: #df2d1f; |
420 | } |
421 | |
422 | +FilesPopup > QListView { |
423 | + border-style: solid; |
424 | + border-width: 1px; |
425 | + border-color: #727272; |
426 | +} |
427 | + |
428 | +FilesPopup > QListView::item { |
429 | + padding: 5px; |
430 | +} |
431 | + |
432 | +FilesPopup > QListView::item:selected { |
433 | + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, |
434 | + stop: 0 #dd4814,stop: 1.0 #b93f14); |
435 | +} |
436 | + |
437 | QAbstractItemView { |
438 | border-style: solid; |
439 | border-top-width: 1px; |
440 | @@ -358,3 +383,43 @@ |
441 | padding-bottom: 5px; |
442 | /* end of hack */ |
443 | } |
444 | + |
445 | +QPushButton#action_button { |
446 | + margin: 0px; |
447 | + padding: 5 5 5 5; |
448 | +} |
449 | + |
450 | +QPushButton#open_in_browser { |
451 | + background: transparent; |
452 | + border: none; |
453 | + text-decoration: underline; |
454 | + color: #dd4814; |
455 | + padding-left: 0px; |
456 | + padding-right: 25px; |
457 | + background-image: url(:/external_icon_orange.png); |
458 | + background-repeat: no-repeat; |
459 | + background-position: right; |
460 | + background-origin: margin; |
461 | +} |
462 | + |
463 | +QPushButton#back_to_file_list { |
464 | + background: transparent; |
465 | + border: none; |
466 | + color: #dd4814; |
467 | + padding-left: 10px; |
468 | + padding-right: 15px; |
469 | +} |
470 | + |
471 | +QPushButton#enhanced_borderless { |
472 | + background: transparent; |
473 | + border: none; |
474 | + padding: 0 5 0 0; |
475 | +} |
476 | + |
477 | +QLabel#lbl_path { |
478 | + color: gray; |
479 | +} |
480 | + |
481 | +QLineEdit#line_copy_link { |
482 | + color: #dd4814; |
483 | +} |
484 | |
485 | === modified file 'ubuntuone/controlpanel/backend.py' |
486 | --- ubuntuone/controlpanel/backend.py 2012-08-16 17:12:44 +0000 |
487 | +++ ubuntuone/controlpanel/backend.py 2012-08-29 18:07:21 +0000 |
488 | @@ -829,12 +829,47 @@ |
489 | |
490 | @log_call(logger.info) |
491 | @inlineCallbacks |
492 | + def get_public_files(self): |
493 | + """Trigger the action to get the public files.""" |
494 | + yield self.sd_client.get_public_files() |
495 | + |
496 | + @log_call(logger.info) |
497 | + @inlineCallbacks |
498 | + def set_public_files_list_handler(self, handler): |
499 | + """Return the handler to be called for the public files list.""" |
500 | + result = yield self.sd_client.set_public_files_list_handler(handler) |
501 | + returnValue(result) |
502 | + |
503 | + @log_call(logger.info) |
504 | + @inlineCallbacks |
505 | def get_shares(self): |
506 | - """Obtain the data to create the sync menu.""" |
507 | + """Get the information of the shares.""" |
508 | result = yield self.sd_client.get_shares() |
509 | returnValue(result) |
510 | |
511 | @log_call(logger.info) |
512 | + @inlineCallbacks |
513 | + def change_public_access(self, path, is_public): |
514 | + """Change the type access of a file.""" |
515 | + yield self.sd_client.change_public_access(path, is_public) |
516 | + |
517 | + @log_call(logger.info) |
518 | + @inlineCallbacks |
519 | + def set_public_access_changed_handler(self, handler): |
520 | + """Return the handler to be called when a access type change.""" |
521 | + result = yield self.sd_client.set_public_access_changed_handler( |
522 | + handler) |
523 | + returnValue(result) |
524 | + |
525 | + @log_call(logger.info) |
526 | + @inlineCallbacks |
527 | + def set_public_access_change_error_handler(self, handler): |
528 | + """Return the handler to be called on access type change error.""" |
529 | + result = yield self.sd_client.set_public_access_change_error_handler( |
530 | + handler) |
531 | + returnValue(result) |
532 | + |
533 | + @log_call(logger.info) |
534 | def shutdown(self): |
535 | """Stop this service.""" |
536 | # do any other needed cleanup |
537 | |
538 | === modified file 'ubuntuone/controlpanel/gui/__init__.py' |
539 | --- ubuntuone/controlpanel/gui/__init__.py 2012-08-20 21:02:06 +0000 |
540 | +++ ubuntuone/controlpanel/gui/__init__.py 2012-08-29 18:07:21 +0000 |
541 | @@ -105,6 +105,7 @@ |
542 | COMPUTER_TO_CLOUD_TITLE = _('Syncing your computer with the cloud') |
543 | CONNECT_BUTTON_LABEL = _('Connect to Ubuntu One') |
544 | CONTACTS = _('Thunderbird plug-in') |
545 | +COPY_LINK = _('Copy link') |
546 | CREDENTIALS_ERROR = _('There was a problem while retrieving the credentials.') |
547 | DASHBOARD_BUTTON_TOOLTIP = _('View your personal details and service ' |
548 | 'summary') |
549 | @@ -226,6 +227,7 @@ |
550 | NO_DEVICES = _('No devices to show.') |
551 | NO_FOLDERS = _('No folders to show.') |
552 | NO_PAIRING_RECORD = _('There is no Ubuntu One pairing record.') |
553 | +OPEN = _('Open') |
554 | OPEN_UBUNTU_ONE = _('Open Ubuntu One') |
555 | OPEN_UBUNTU_ONE_FOLDER = _('Open the Ubuntu One Folder') |
556 | PERCENTAGE_LABEL = _('%(percentage)s used') |
557 | |
558 | === modified file 'ubuntuone/controlpanel/gui/qt/addfolder.py' |
559 | --- ubuntuone/controlpanel/gui/qt/addfolder.py 2012-03-19 20:55:52 +0000 |
560 | +++ ubuntuone/controlpanel/gui/qt/addfolder.py 2012-08-29 18:07:21 +0000 |
561 | @@ -33,13 +33,13 @@ |
562 | logger = setup_logging('qt.addfolder') |
563 | |
564 | CLOSE = QtGui.QMessageBox.Close |
565 | -# NOTE: this is temporary because of a Qt bug that will be fixed |
566 | -# on Qt 4.9. You cannot, in general, use sys.platform in these |
567 | +# NOTE: this is temporary because of Qt bugs. |
568 | +# You cannot, in general, use sys.platform in these |
569 | # modules. Do not do this. Please. This is an exception, one |
570 | # time only, pinky-swear, cross my heart and hope to die if |
571 | # I lie. |
572 | FILE_CHOOSER_OPTIONS = QtGui.QFileDialog.ShowDirsOnly |
573 | -if sys.platform == 'win32': |
574 | +if sys.platform in ('win32', 'darwin'): |
575 | FILE_CHOOSER_OPTIONS |= QtGui.QFileDialog.DontUseNativeDialog |
576 | # Yes, that is true. If you do that again, you will be hunted |
577 | # down and taught a lesson. You will be sorry. |
578 | |
579 | === modified file 'ubuntuone/controlpanel/gui/qt/main/__init__.py' |
580 | --- ubuntuone/controlpanel/gui/qt/main/__init__.py 2012-08-20 20:30:39 +0000 |
581 | +++ ubuntuone/controlpanel/gui/qt/main/__init__.py 2012-08-29 18:07:21 +0000 |
582 | @@ -85,6 +85,8 @@ |
583 | # because u1trial already provides a reactor. |
584 | |
585 | args = ['ubuntuone-installer'] + args |
586 | + if sys.platform == 'darwin': |
587 | + args += ['-graphicssystem', 'raster'] |
588 | app = UniqueApplication(args, "ubuntuone-control-panel") |
589 | |
590 | # on darwin, must install qt4reactor after UniqueApplication init. |
591 | |
592 | === modified file 'ubuntuone/controlpanel/gui/qt/main/tests/test_main.py' |
593 | --- ubuntuone/controlpanel/gui/qt/main/tests/test_main.py 2012-08-04 00:05:23 +0000 |
594 | +++ ubuntuone/controlpanel/gui/qt/main/tests/test_main.py 2012-08-29 18:07:21 +0000 |
595 | @@ -47,11 +47,17 @@ |
596 | self.style = None |
597 | self.translator = None |
598 | self.new_instance = FakeSignal() |
599 | + self.raster = False |
600 | |
601 | def __call__(self, argv, *args, **kwargs): |
602 | """Fake arg filtering function.""" |
603 | - if '-title' in argv: |
604 | - argv.remove('-title') |
605 | + if 'raster' in argv and '-graphicssystem' in argv: |
606 | + self.raster = True |
607 | + for arg in ('-title', '-graphicssystem', 'raster'): |
608 | + try: |
609 | + argv.remove(arg) |
610 | + except ValueError: |
611 | + pass |
612 | self.args = (argv, args, kwargs) |
613 | return self |
614 | |
615 | @@ -222,6 +228,18 @@ |
616 | self.assertEqual(self.start.args[1], |
617 | {'minimized': True, 'with_icon': True, 'installer': False}) |
618 | |
619 | + def test_nondarwin_is_not_raster(self): |
620 | + """Ensure the raster argument is not injected in non-darwin.""" |
621 | + self.patch(sys, 'platform', 'not-darwin') |
622 | + main.main([sys.argv[0]]) |
623 | + self.assertFalse(self.app.raster) |
624 | + |
625 | + def test_darwin_is_raster(self): |
626 | + """Ensure the raster argument is injected in darwin.""" |
627 | + self.patch(sys, 'platform', 'darwin') |
628 | + main.main([sys.argv[0]]) |
629 | + self.assertTrue(self.app.raster) |
630 | + |
631 | def test_translator(self): |
632 | """Ensure the Qt translator is loaded.""" |
633 | main.main([sys.argv[0]]) |
634 | |
635 | === modified file 'ubuntuone/controlpanel/gui/qt/preferences.py' |
636 | --- ubuntuone/controlpanel/gui/qt/preferences.py 2012-05-15 18:43:52 +0000 |
637 | +++ ubuntuone/controlpanel/gui/qt/preferences.py 2012-08-29 18:07:21 +0000 |
638 | @@ -121,12 +121,14 @@ |
639 | notifications = self.ui.show_all_notifications_checkbox.checkState() |
640 | share_autosubscribe = self.ui.share_autosubscribe_checkbox.checkState() |
641 | udf_autosubscribe = self.ui.udf_autosubscribe_checkbox.checkState() |
642 | - download_speed = self.ui.download_speed_spinbox.value() * KILOBYTES |
643 | if self.ui.limit_uploads_checkbox.checkState() == UNCHECKED: |
644 | upload_speed = -1 |
645 | - upload_speed = self.ui.upload_speed_spinbox.value() * KILOBYTES |
646 | + else: |
647 | + upload_speed = self.ui.upload_speed_spinbox.value() * KILOBYTES |
648 | if self.ui.limit_downloads_checkbox.checkState() == UNCHECKED: |
649 | download_speed = -1 |
650 | + else: |
651 | + download_speed = self.ui.download_speed_spinbox.value() * KILOBYTES |
652 | |
653 | settings = { |
654 | backend.AUTOCONNECT_KEY: autoconnect == CHECKED, |
655 | |
656 | === added file 'ubuntuone/controlpanel/gui/qt/share_file.py' |
657 | --- ubuntuone/controlpanel/gui/qt/share_file.py 1970-01-01 00:00:00 +0000 |
658 | +++ ubuntuone/controlpanel/gui/qt/share_file.py 2012-08-29 18:07:21 +0000 |
659 | @@ -0,0 +1,63 @@ |
660 | +# -*- coding: utf-8 -*- |
661 | +# |
662 | +# Copyright 2012 Canonical Ltd. |
663 | +# |
664 | +# This program is free software: you can redistribute it and/or modify it |
665 | +# under the terms of the GNU General Public License version 3, as published |
666 | +# by the Free Software Foundation. |
667 | +# |
668 | +# This program is distributed in the hope that it will be useful, but |
669 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
670 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
671 | +# PURPOSE. See the GNU General Public License for more details. |
672 | +# |
673 | +# You should have received a copy of the GNU General Public License along |
674 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
675 | + |
676 | +"""The UI for Share file widget.""" |
677 | + |
678 | +import os |
679 | + |
680 | +from PyQt4 import QtGui, QtCore |
681 | + |
682 | +from ubuntuone.controlpanel import cache |
683 | +from ubuntuone.controlpanel.gui.qt.share_links_search import ( |
684 | + get_system_icon_for_filename, |
685 | +) |
686 | +from ubuntuone.controlpanel.gui.qt.ui import share_file_ui |
687 | +from ubuntuone.controlpanel.logger import setup_logging |
688 | + |
689 | + |
690 | +logger = setup_logging('qt.share_file') |
691 | + |
692 | + |
693 | +class ShareFileWidget(cache.Cache, QtGui.QWidget): |
694 | + """Widget with the detail information about the shared file.""" |
695 | + |
696 | + linkDisabled = QtCore.pyqtSignal() |
697 | + |
698 | + def __init__(self, file_path='', *args, **kwargs): |
699 | + super(ShareFileWidget, self).__init__(*args, **kwargs) |
700 | + self.ui = share_file_ui.Ui_Form() |
701 | + self.ui.setupUi(self) |
702 | + self.file_path = file_path |
703 | + |
704 | + self.ui.lbl_filename.setText(os.path.basename(file_path)) |
705 | + self.ui.lbl_path.setText(file_path) |
706 | + icon = get_system_icon_for_filename(os.path.expanduser(file_path)) |
707 | + pixmap = icon.pixmap(24) |
708 | + self.ui.lbl_icon.setPixmap(pixmap) |
709 | + |
710 | + self.ui.btn_open.clicked.connect(self.open_file) |
711 | + self.ui.btn_disable.clicked.connect(self.disable_link) |
712 | + |
713 | + def open_file(self): |
714 | + """Open the specified file.""" |
715 | + path = u'file://%s' % self.file_path |
716 | + QtGui.QDesktopServices.openUrl(QtCore.QUrl(path)) |
717 | + |
718 | + def disable_link(self, val): |
719 | + """Change the access of the file to Not Public.""" |
720 | + self.backend.change_public_access( |
721 | + os.path.expanduser(self.file_path), False) |
722 | + self.linkDisabled.emit() |
723 | |
724 | === modified file 'ubuntuone/controlpanel/gui/qt/share_links.py' |
725 | --- ubuntuone/controlpanel/gui/qt/share_links.py 2012-08-20 18:22:07 +0000 |
726 | +++ ubuntuone/controlpanel/gui/qt/share_links.py 2012-08-29 18:07:21 +0000 |
727 | @@ -16,27 +16,215 @@ |
728 | |
729 | """The user interface for the control panel for Ubuntu One.""" |
730 | |
731 | +import os |
732 | + |
733 | +from PyQt4 import QtGui, QtCore |
734 | +from twisted.internet.defer import inlineCallbacks |
735 | + |
736 | from ubuntuone.controlpanel.logger import setup_logging |
737 | from ubuntuone.controlpanel.gui import ( |
738 | + COPY_LINK, |
739 | + OPEN, |
740 | SEARCH_FILES, |
741 | SHARED_FILES, |
742 | ) |
743 | |
744 | -from ubuntuone.controlpanel.gui.qt.ui import share_links_ui |
745 | +# Unused import images_rc, pylint: disable=W0611 |
746 | +from ubuntuone.controlpanel.gui.qt.ui import ( |
747 | + images_rc, |
748 | + share_links_ui, |
749 | +) |
750 | +# pylint: enable=W0611 |
751 | +from ubuntuone.controlpanel.gui.qt.share_file import ShareFileWidget |
752 | +from ubuntuone.controlpanel.gui.qt.share_links_search import ( |
753 | + get_system_icon_for_filename, |
754 | +) |
755 | from ubuntuone.controlpanel.gui.qt.ubuntuonebin import UbuntuOneBin |
756 | |
757 | |
758 | logger = setup_logging('qt.share_links') |
759 | |
760 | |
761 | +FILE_NAME_COL = 0 |
762 | +PUBLIC_LINK_COL = 1 |
763 | +ACTIONS_COL = 2 |
764 | + |
765 | + |
766 | class ShareLinksPanel(UbuntuOneBin): |
767 | """The Share Links Tab Panel widget""" |
768 | |
769 | ui_class = share_links_ui |
770 | logger = logger |
771 | + _enhanced_line = None |
772 | + home_dir = '' |
773 | |
774 | def _setup(self): |
775 | """Do some extra setupping for the UI.""" |
776 | super(ShareLinksPanel, self)._setup() |
777 | + self.home_dir = '' |
778 | self.ui.search_files_lbl.setText(SEARCH_FILES) |
779 | self.ui.shared_group.setTitle(SHARED_FILES) |
780 | + |
781 | + # Set enhanced line edits |
782 | + self._enhanced_line = EnhancedLineEdit(self.ui.line_search, |
783 | + self._line_close_btn, icon=":/delete_search.png", |
784 | + style='enhanced_borderless') |
785 | + self._enhanced_line.btn_operation.hide() |
786 | + self.ui.line_search.popup.popupHidden.connect( |
787 | + self._hide_line_btn_close_hide) |
788 | + self.ui.line_search.popup.popupShown.connect( |
789 | + self._hide_line_btn_close_show) |
790 | + EnhancedLineEdit(self.ui.line_copy_link, self._copy_link_from_line, |
791 | + text=COPY_LINK) |
792 | + |
793 | + self.ui.line_search.itemSelected.connect(self.share_file) |
794 | + self.ui.back_to_file_list.clicked.connect(self._move_to_main_list) |
795 | + self.ui.open_in_browser.clicked.connect(self._open_in_browser) |
796 | + |
797 | + # Connect backend signals |
798 | + self.backend.set_public_files_list_handler(self._load_public_files) |
799 | + self.backend.set_public_access_changed_handler(self._file_shared) |
800 | + self.backend.set_public_access_change_error_handler( |
801 | + lambda: self._set_is_processing(False)) |
802 | + self.get_public_files() |
803 | + |
804 | + @inlineCallbacks |
805 | + def share_file(self, file_path): |
806 | + """Clean the previous file share details and publish file_path.""" |
807 | + if self.ui.hbox_share_file.count() > 0: |
808 | + widget = self.ui.hbox_share_file.takeAt(0).widget() |
809 | + widget.close() |
810 | + self.is_processing = True |
811 | + file_path = unicode(file_path) |
812 | + share_file_widget = ShareFileWidget(file_path) |
813 | + self.ui.hbox_share_file.addWidget(share_file_widget) |
814 | + share_file_widget.linkDisabled.connect( |
815 | + lambda: self.ui.line_copy_link.setText('')) |
816 | + yield self.backend.change_public_access( |
817 | + os.path.expanduser(file_path), True) |
818 | + |
819 | + def _file_shared(self, info): |
820 | + """Receive the notification that the file has been published.""" |
821 | + url = info.get("public_url") |
822 | + self.ui.line_copy_link.setText(url) |
823 | + self.ui.stacked_widget.setCurrentIndex(1) |
824 | + self.is_processing = False |
825 | + |
826 | + def _open_in_browser(self): |
827 | + """Open the link in line_copy_link in the browser.""" |
828 | + url = self.ui.line_copy_link.text() |
829 | + QtGui.QDesktopServices.openUrl(QtCore.QUrl(url)) |
830 | + |
831 | + def _copy_link_from_line(self): |
832 | + """Copy link into clipboard from line edit.""" |
833 | + app = QtGui.QApplication.instance() |
834 | + app.clipboard().setText(self.ui.line_copy_link.text()) |
835 | + |
836 | + def _move_to_main_list(self): |
837 | + """Set the share files list as current widget.""" |
838 | + self.ui.stacked_widget.setCurrentIndex(0) |
839 | + self.get_public_files() |
840 | + |
841 | + @inlineCallbacks |
842 | + def get_public_files(self): |
843 | + """Request the list of public files.""" |
844 | + self.is_processing = True |
845 | + self.home_dir = yield self.backend.get_home_dir() |
846 | + yield self.backend.get_public_files() |
847 | + |
848 | + def _load_public_files(self, publicfiles): |
849 | + """Load the list of public files.""" |
850 | + self.ui.tree_shared_files.clear() |
851 | + for pfile in publicfiles: |
852 | + item = QtGui.QTreeWidgetItem() |
853 | + path = pfile['path'] |
854 | + public_url = pfile['public_url'] |
855 | + name = os.path.basename(path) |
856 | + item.setText(FILE_NAME_COL, name) |
857 | + tooltip = path |
858 | + if tooltip.startswith(self.home_dir): |
859 | + tooltip = tooltip.replace(self.home_dir, '~', 1) |
860 | + item.setToolTip(FILE_NAME_COL, tooltip) |
861 | + icon = get_system_icon_for_filename(path) |
862 | + item.setIcon(FILE_NAME_COL, icon) |
863 | + |
864 | + self.ui.tree_shared_files.setColumnWidth(PUBLIC_LINK_COL, 300) |
865 | + item.setSizeHint(FILE_NAME_COL, QtCore.QSize(-1, 35)) |
866 | + self.ui.tree_shared_files.addTopLevelItem(item) |
867 | + |
868 | + link = ('<a href="%s"><span style="font-size: 12px;' |
869 | + 'color: #dd4814";>%s</span></a>' |
870 | + % (public_url, public_url)) |
871 | + label = QtGui.QLabel(link, self.ui.tree_shared_files) |
872 | + label.setOpenExternalLinks(True) |
873 | + self.ui.tree_shared_files.setItemWidget(item, PUBLIC_LINK_COL, |
874 | + label) |
875 | + |
876 | + actions = ActionsButtons(path, public_url, |
877 | + self.ui.tree_shared_files) |
878 | + self.ui.tree_shared_files.setItemWidget(item, ACTIONS_COL, actions) |
879 | + self.is_processing = False |
880 | + |
881 | + def _line_close_btn(self): |
882 | + """Close button in the line edit was pressed, hide the popup.""" |
883 | + self.ui.line_search.popup.hide() |
884 | + self.ui.line_search.setFocus() |
885 | + |
886 | + def _hide_line_btn_close_hide(self): |
887 | + """Hide the button inside the search line edit-""" |
888 | + self._enhanced_line.btn_operation.hide() |
889 | + |
890 | + def _hide_line_btn_close_show(self): |
891 | + """Show the button inside the search line edit-""" |
892 | + self._enhanced_line.btn_operation.show() |
893 | + |
894 | + |
895 | +class ActionsButtons(QtGui.QWidget): |
896 | + """Widget that contains the open and copy link actions on the list.""" |
897 | + |
898 | + def __init__(self, path, link, parent=None): |
899 | + super(ActionsButtons, self).__init__(parent) |
900 | + self.path = path |
901 | + self.link = link |
902 | + |
903 | + hbox = QtGui.QHBoxLayout(self) |
904 | + btn_open = QtGui.QPushButton(OPEN) |
905 | + btn_copy = QtGui.QPushButton(COPY_LINK) |
906 | + btn_open.setObjectName('action_button') |
907 | + btn_copy.setObjectName('action_button') |
908 | + hbox.addSpacerItem(QtGui.QSpacerItem(1, 0, |
909 | + QtGui.QSizePolicy.Expanding)) |
910 | + hbox.addWidget(btn_open) |
911 | + hbox.addWidget(btn_copy) |
912 | + |
913 | + btn_open.clicked.connect(self.open) |
914 | + btn_copy.clicked.connect(self.copy) |
915 | + |
916 | + def open(self): |
917 | + """Open the file.""" |
918 | + file_path = u'file://%s' % self.path |
919 | + QtGui.QDesktopServices.openUrl(QtCore.QUrl(file_path)) |
920 | + |
921 | + def copy(self): |
922 | + """Copy the public link of the file in the clipboard.""" |
923 | + app = QtGui.QApplication.instance() |
924 | + app.clipboard().setText(self.link) |
925 | + |
926 | + |
927 | +class EnhancedLineEdit(object): |
928 | + """Add a button inside the QLineEdit received.""" |
929 | + |
930 | + def __init__(self, line_edit, operation, text=None, icon=None, style=None): |
931 | + hbox = QtGui.QHBoxLayout(line_edit) |
932 | + hbox.setMargin(0) |
933 | + line_edit.setLayout(hbox) |
934 | + hbox.addStretch() |
935 | + self.btn_operation = QtGui.QPushButton(line_edit) |
936 | + if text: |
937 | + self.btn_operation.setText(text) |
938 | + if icon: |
939 | + self.btn_operation.setIcon(QtGui.QIcon(icon)) |
940 | + if style: |
941 | + self.btn_operation.setObjectName(style) |
942 | + hbox.addWidget(self.btn_operation) |
943 | + self.btn_operation.clicked.connect(operation) |
944 | |
945 | === added file 'ubuntuone/controlpanel/gui/qt/share_links_search.py' |
946 | --- ubuntuone/controlpanel/gui/qt/share_links_search.py 1970-01-01 00:00:00 +0000 |
947 | +++ ubuntuone/controlpanel/gui/qt/share_links_search.py 2012-08-29 18:07:21 +0000 |
948 | @@ -0,0 +1,318 @@ |
949 | +# -*- coding: utf-8 *-* |
950 | + |
951 | +# Copyright 2012 Canonical Ltd. |
952 | +# |
953 | +# This program is free software: you can redistribute it and/or modify it |
954 | +# under the terms of the GNU General Public License version 3, as published |
955 | +# by the Free Software Foundation. |
956 | +# |
957 | +# This program is distributed in the hope that it will be useful, but |
958 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
959 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
960 | +# PURPOSE. See the GNU General Public License for more details. |
961 | +# |
962 | +# You should have received a copy of the GNU General Public License along |
963 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
964 | + |
965 | +"""The search and popup widgets for the Share Links tab.""" |
966 | + |
967 | +import os |
968 | + |
969 | +from PyQt4 import QtGui, QtCore |
970 | +from twisted.internet.defer import inlineCallbacks |
971 | + |
972 | +from ubuntuone.controlpanel import cache |
973 | + |
974 | + |
975 | +def get_system_icon_for_filename(file_path): |
976 | + """Return the icon used for the system to represent this file.""" |
977 | + fileinfo = QtCore.QFileInfo(os.path.expanduser(file_path)) |
978 | + icon_provider = QtGui.QFileIconProvider() |
979 | + icon = icon_provider.icon(fileinfo) |
980 | + return icon |
981 | + |
982 | + |
983 | +# pylint: disable=C0103 |
984 | + |
985 | +class SearchBox(QtGui.QLineEdit, cache.Cache): |
986 | + """Search widget for the synced files.""" |
987 | + |
988 | + itemSelected = QtCore.pyqtSignal(unicode) |
989 | + |
990 | + def __init__(self, parent=None): |
991 | + super(SearchBox, self).__init__(parent) |
992 | + self.popup = FilesPopup() |
993 | + self.home_dir = '' |
994 | + self.temp_u1_files = [] |
995 | + self.items_per_page = 0 |
996 | + self.items_step = 20 |
997 | + self.prefix = '' |
998 | + self._thread_explore = None |
999 | + self._pre_key_event = { |
1000 | + QtCore.Qt.Key_Space: self._key_space_pressed, |
1001 | + } |
1002 | + self._post_key_event = { |
1003 | + QtCore.Qt.Key_Escape: lambda *args: self.popup.hide(), |
1004 | + QtCore.Qt.Key_Down: self._key_down_pressed, |
1005 | + QtCore.Qt.Key_Up: self._key_up_pressed, |
1006 | + QtCore.Qt.Key_Return: self._key_return_pressed, |
1007 | + QtCore.Qt.Key_Enter: self._key_return_pressed, |
1008 | + } |
1009 | + |
1010 | + self.textChanged.connect(self.filter) |
1011 | + |
1012 | + self._get_volumes_info() |
1013 | + |
1014 | + @inlineCallbacks |
1015 | + def _get_volumes_info(self): |
1016 | + """Get the volumes info.""" |
1017 | + self.home_dir = yield self.backend.get_home_dir() |
1018 | + self._thread_explore = ThreadExploreFolder(self.home_dir) |
1019 | + info = yield self.backend.volumes_info() |
1020 | + self._process_volumes_info(info) |
1021 | + |
1022 | + def _process_volumes_info(self, info): |
1023 | + """Get the volumes paths and process them.""" |
1024 | + folders = [] |
1025 | + for _, _, data in info: |
1026 | + for d in data: |
1027 | + folder = d.get('path', d.get('realpath')) |
1028 | + folders.append(folder) |
1029 | + self.get_folders_files(folders) |
1030 | + |
1031 | + def get_folders_files(self, folders): |
1032 | + """Get the list of files in each folder and index them.""" |
1033 | + self._thread_explore.set_folders(folders) |
1034 | + self._thread_explore.folderDataObtained.connect( |
1035 | + self._folder_content_obtained) |
1036 | + self._thread_explore.start() |
1037 | + |
1038 | + def _folder_content_obtained(self): |
1039 | + """Receive the content of the folders from the thread.""" |
1040 | + files = self._get_filtered_list(self._thread_explore.u1_files) |
1041 | + self.popup.load_items(files) |
1042 | + text = self.text() |
1043 | + self.filter(text) |
1044 | + |
1045 | + def filter(self, text): |
1046 | + """Filter the content of the popup with the text entered.""" |
1047 | + text = unicode(text) |
1048 | + self.items_per_page = 0 |
1049 | + if text and (self.prefix == '' or self.prefix != text[:-1]): |
1050 | + self.prefix = text |
1051 | + self.temp_u1_files = self._thread_explore.u1_files |
1052 | + self._show_filter() |
1053 | + elif text != '': |
1054 | + self.prefix = text |
1055 | + self._show_filter() |
1056 | + else: |
1057 | + self.popup.hide() |
1058 | + |
1059 | + def _show_filter(self): |
1060 | + """Load the items in the popup and display it.""" |
1061 | + if not self.popup.isVisible(): |
1062 | + self.popup.setFixedWidth(self.width()) |
1063 | + point = self.parent().mapToGlobal(self.pos()) |
1064 | + self.popup.show() |
1065 | + self.popup.move(point.x(), point.y() + self.height()) |
1066 | + |
1067 | + self.temp_u1_files = [filename for filename in self.temp_u1_files |
1068 | + if os.path.basename(filename).find(self.prefix) > -1] |
1069 | + files = self._get_filtered_list(self.temp_u1_files) |
1070 | + self.popup.load_items(files) |
1071 | + |
1072 | + def _get_filtered_list(self, filenames): |
1073 | + """Get pages of results.""" |
1074 | + begin = self.items_per_page |
1075 | + self.items_per_page += self.items_step |
1076 | + files = [filename for filename in filenames[begin:self.items_per_page]] |
1077 | + return files |
1078 | + |
1079 | + def _key_space_pressed(self): |
1080 | + """The user pressed the space key.""" |
1081 | + item = self.popup.list_widget.currentItem() |
1082 | + widget = self.popup.list_widget.itemWidget(item) |
1083 | + self.setText(widget.name) |
1084 | + self.popup.hide() |
1085 | + return True |
1086 | + |
1087 | + def _key_down_pressed(self, current): |
1088 | + """The user pressed the down key.""" |
1089 | + #While the current position is lower that the list size go to next |
1090 | + if current != self.popup.list_widget.count() - 1: |
1091 | + self.popup.list_widget.setCurrentRow( |
1092 | + self.popup.list_widget.currentRow() + 1) |
1093 | + #If the current position is greater than the amount of items in |
1094 | + #the list - 6, then try to fetch more items in the list. |
1095 | + if current >= (self.popup.list_widget.count() - 6): |
1096 | + filenames = self._get_filtered_list(self.temp_u1_files) |
1097 | + self.popup.fetch_more(filenames) |
1098 | + |
1099 | + def _key_up_pressed(self, current): |
1100 | + """The user pressed the up key.""" |
1101 | + #while the current position is greater than 0, go to previous |
1102 | + if current > 0: |
1103 | + self.popup.list_widget.setCurrentRow( |
1104 | + self.popup.list_widget.currentRow() - 1) |
1105 | + |
1106 | + def _key_return_pressed(self, current): |
1107 | + """The user pressed the return key.""" |
1108 | + #If the user pressed enter, go to the item selected |
1109 | + item = self.popup.list_widget.currentItem() |
1110 | + self._set_selected_item(item) |
1111 | + |
1112 | + def keyPressEvent(self, event): |
1113 | + """Process the different behaviour for the keyPress event.""" |
1114 | + if self._pre_key_event.get(event.key(), lambda: False)(): |
1115 | + return |
1116 | + |
1117 | + super(SearchBox, self).keyPressEvent(event) |
1118 | + current = self.popup.list_widget.currentRow() |
1119 | + self._post_key_event.get(event.key(), lambda *args: None)(current) |
1120 | + |
1121 | + def focusOutEvent(self, event): |
1122 | + """Hide the popup when the window loses the focus.""" |
1123 | + super(SearchBox, self).focusOutEvent(event) |
1124 | + self.popup.hide() |
1125 | + |
1126 | + def _set_selected_item(self, item): |
1127 | + """Notify of the selected item.""" |
1128 | + widget = self.popup.list_widget.itemWidget(item) |
1129 | + self.itemSelected.emit(widget.file_path) |
1130 | + self.setText('') |
1131 | + self.popup.hide() |
1132 | + |
1133 | + def moveEvent(self, event): |
1134 | + """Move the popup when the windows is moved.""" |
1135 | + super(SearchBox, self).moveEvent(event) |
1136 | + if self.popup.isVisible(): |
1137 | + point = self.mapToGlobal(self.line_search.pos()) |
1138 | + self.popup.move(point.x(), point.y() + self.line_search.height()) |
1139 | + |
1140 | + |
1141 | +class FileItem(QtGui.QLabel): |
1142 | + """Create a styled QLabel that will show the info.""" |
1143 | + |
1144 | + def __init__(self, file_path): |
1145 | + super(FileItem, self).__init__() |
1146 | + self.name = os.path.basename(file_path) |
1147 | + self.file_path = file_path |
1148 | + self.text_style = (u"<span style='color: {2};'>{0}</span><br>" |
1149 | + "<span style='font-size: 13px; color: {3};'>({1})</span>") |
1150 | + self.setText(self.text_style.format( |
1151 | + self.name, self.file_path, '#333333', 'grey')) |
1152 | + |
1153 | + def set_selected(self): |
1154 | + """Set a style for the text when the item is selected.""" |
1155 | + self.setText(self.text_style.format( |
1156 | + self.name, self.file_path, 'white', 'white')) |
1157 | + |
1158 | + def set_not_selected(self): |
1159 | + """Set a style for the text when the item is not selected.""" |
1160 | + self.setText(self.text_style.format( |
1161 | + self.name, self.file_path, '#333333', 'grey')) |
1162 | + |
1163 | + |
1164 | +class FilesPopup(QtGui.QFrame): |
1165 | + """Filter popup where the file names are shown.""" |
1166 | + |
1167 | + popupShown = QtCore.pyqtSignal() |
1168 | + popupHidden = QtCore.pyqtSignal() |
1169 | + |
1170 | + def __init__(self): |
1171 | + super(FilesPopup, self).__init__(None, |
1172 | + QtCore.Qt.FramelessWindowHint | QtCore.Qt.ToolTip) |
1173 | + vbox = QtGui.QVBoxLayout(self) |
1174 | + vbox.setContentsMargins(0, 0, 0, 0) |
1175 | + vbox.setSpacing(0) |
1176 | + self.list_widget = QtGui.QListWidget() |
1177 | + self.list_widget.setMinimumHeight(270) |
1178 | + vbox.addWidget(self.list_widget) |
1179 | + |
1180 | + self.list_widget.currentItemChanged.connect(self._repaint_items) |
1181 | + |
1182 | + def _repaint_items(self, current, previous): |
1183 | + """Set the proper style for the current and previous items.""" |
1184 | + if current is not None: |
1185 | + widget = self.list_widget.itemWidget(current) |
1186 | + widget.set_selected() |
1187 | + if previous is not None: |
1188 | + widget = self.list_widget.itemWidget(previous) |
1189 | + widget.set_not_selected() |
1190 | + |
1191 | + def load_items(self, file_items): |
1192 | + """Load the initial items.""" |
1193 | + self.list_widget.clear() |
1194 | + for file_ in file_items: |
1195 | + item = QtGui.QListWidgetItem("\n") |
1196 | + file_widget = FileItem(file_) |
1197 | + self.list_widget.addItem(item) |
1198 | + self.list_widget.setItemWidget(item, file_widget) |
1199 | + icon = get_system_icon_for_filename(file_) |
1200 | + item.setIcon(icon) |
1201 | + if file_items: |
1202 | + self.list_widget.setCurrentRow(0) |
1203 | + |
1204 | + def fetch_more(self, file_items): |
1205 | + """Add more items to the list on user scroll.""" |
1206 | + for file_ in file_items: |
1207 | + item = QtGui.QListWidgetItem("\n") |
1208 | + file_widget = FileItem(file_) |
1209 | + self.list_widget.addItem(item) |
1210 | + self.list_widget.setItemWidget(item, file_widget) |
1211 | + icon = get_system_icon_for_filename(file_) |
1212 | + item.setIcon(icon) |
1213 | + |
1214 | + def showEvent(self, event): |
1215 | + """Notify when the popup is shown.""" |
1216 | + super(FilesPopup, self).showEvent(event) |
1217 | + self.popupShown.emit() |
1218 | + |
1219 | + def hideEvent(self, event): |
1220 | + """Notify when the popup is hidden.""" |
1221 | + super(FilesPopup, self).hideEvent(event) |
1222 | + self.popupHidden.emit() |
1223 | + |
1224 | + |
1225 | +class ThreadExploreFolder(QtCore.QThread): |
1226 | + """Retrieve the data of the folders asynchronously.""" |
1227 | + |
1228 | + folderDataObtained = QtCore.pyqtSignal() |
1229 | + |
1230 | + def __init__(self, home_dir=''): |
1231 | + super(ThreadExploreFolder, self).__init__() |
1232 | + self.home_dir = home_dir |
1233 | + self.u1_files = [] |
1234 | + self.folders = [] |
1235 | + |
1236 | + def set_folders(self, folders): |
1237 | + """Set the folders to be explored.""" |
1238 | + self.folders = folders |
1239 | + |
1240 | + def run(self): |
1241 | + """Execute the thread to obtain the folders data.""" |
1242 | + folders_data = [] |
1243 | + for folder in self.folders: |
1244 | + folders_data += self.get_folder_info(folder) |
1245 | + temp_files = [] |
1246 | + for file_ in folders_data: |
1247 | + if file_.startswith(self.home_dir): |
1248 | + new_path = file_[len(self.home_dir):] |
1249 | + if new_path.startswith(os.path.sep): |
1250 | + new_path = new_path[1:] |
1251 | + path = os.path.join('~', new_path) |
1252 | + temp_files.append(path) |
1253 | + else: |
1254 | + temp_files.append(file_) |
1255 | + folders_data = temp_files |
1256 | + folders_data.sort() |
1257 | + self.u1_files = folders_data |
1258 | + self.folderDataObtained.emit() |
1259 | + |
1260 | + def get_folder_info(self, folder): |
1261 | + """Return the list of files in the proper folder.""" |
1262 | + files_list = [] |
1263 | + if os.path.exists(folder): |
1264 | + for root, _, files in os.walk(folder): |
1265 | + files_list.extend([os.path.join(root, f) for f in files]) |
1266 | + return files_list |
1267 | |
1268 | === modified file 'ubuntuone/controlpanel/gui/qt/tests/__init__.py' |
1269 | --- ubuntuone/controlpanel/gui/qt/tests/__init__.py 2012-08-20 14:09:45 +0000 |
1270 | +++ ubuntuone/controlpanel/gui/qt/tests/__init__.py 2012-08-29 18:07:21 +0000 |
1271 | @@ -126,6 +126,7 @@ |
1272 | 'build_signed_iri', |
1273 | 'change_device_settings', |
1274 | 'change_file_sync_settings', |
1275 | + 'change_public_access', |
1276 | 'change_replication_settings', |
1277 | 'change_volume_settings', |
1278 | 'connect_files', |
1279 | @@ -137,12 +138,16 @@ |
1280 | 'enable_files', |
1281 | 'file_sync_settings_info', |
1282 | 'file_sync_status', |
1283 | + 'get_public_files', |
1284 | 'login', |
1285 | 'register', |
1286 | 'remove_device', |
1287 | 'replications_info', |
1288 | 'restart_files', |
1289 | 'restore_file_sync_settings', |
1290 | + 'set_public_access_changed_handler', |
1291 | + 'set_public_access_change_error_handler', |
1292 | + 'set_public_files_list_handler', |
1293 | 'shutdown', |
1294 | 'start_files', |
1295 | 'stop_files', |
1296 | @@ -379,3 +384,16 @@ |
1297 | """The backend instance is correct.""" |
1298 | if getattr(self.ui, 'backend', None) is not None: |
1299 | self.assertIsInstance(self.ui.backend, FakedControlPanelBackend) |
1300 | + |
1301 | + |
1302 | +class FakeDesktopService(object): |
1303 | + """Fake QDesktopService.""" |
1304 | + |
1305 | + def __init__(self): |
1306 | + self.opened_url = None |
1307 | + |
1308 | + # pylint: disable=C0103 |
1309 | + |
1310 | + def openUrl(self, url): |
1311 | + """Fake openUrl.""" |
1312 | + self.opened_url = url |
1313 | |
1314 | === modified file 'ubuntuone/controlpanel/gui/qt/tests/test_preferences.py' |
1315 | --- ubuntuone/controlpanel/gui/qt/tests/test_preferences.py 2012-05-15 18:43:52 +0000 |
1316 | +++ ubuntuone/controlpanel/gui/qt/tests/test_preferences.py 2012-08-29 18:07:21 +0000 |
1317 | @@ -47,8 +47,14 @@ |
1318 | notifs = self.ui.ui.show_all_notifications_checkbox.checkState() |
1319 | share_auto = self.ui.ui.share_autosubscribe_checkbox.checkState() |
1320 | udf_auto = self.ui.ui.udf_autosubscribe_checkbox.checkState() |
1321 | - download_speed = self.ui.ui.download_speed_spinbox.value() |
1322 | - upload_speed = self.ui.ui.upload_speed_spinbox.value() |
1323 | + if self.ui.ui.limit_downloads_checkbox.checkState() == gui.CHECKED: |
1324 | + download_speed = self.ui.ui.download_speed_spinbox.value() |
1325 | + else: |
1326 | + download_speed = -1 |
1327 | + if self.ui.ui.limit_uploads_checkbox.checkState() == gui.CHECKED: |
1328 | + upload_speed = self.ui.ui.upload_speed_spinbox.value() |
1329 | + else: |
1330 | + upload_speed = -1 |
1331 | |
1332 | result = { |
1333 | gui.backend.AUTOCONNECT_KEY: autoconnect == gui.CHECKED, |
1334 | |
1335 | === added file 'ubuntuone/controlpanel/gui/qt/tests/test_share_file.py' |
1336 | --- ubuntuone/controlpanel/gui/qt/tests/test_share_file.py 1970-01-01 00:00:00 +0000 |
1337 | +++ ubuntuone/controlpanel/gui/qt/tests/test_share_file.py 2012-08-29 18:07:21 +0000 |
1338 | @@ -0,0 +1,76 @@ |
1339 | +# -*- coding: utf-8 -*- |
1340 | +# |
1341 | +# Copyright 2012 Canonical Ltd. |
1342 | +# |
1343 | +# This program is free software: you can redistribute it and/or modify it |
1344 | +# under the terms of the GNU General Public License version 3, as published |
1345 | +# by the Free Software Foundation. |
1346 | +# |
1347 | +# This program is distributed in the hope that it will be useful, but |
1348 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
1349 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1350 | +# PURPOSE. See the GNU General Public License for more details. |
1351 | +# |
1352 | +# You should have received a copy of the GNU General Public License along |
1353 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
1354 | + |
1355 | +"""Tests for the share file widget.""" |
1356 | + |
1357 | +import os |
1358 | + |
1359 | +from PyQt4 import QtGui, QtCore |
1360 | + |
1361 | +from ubuntuone.controlpanel.gui.qt import share_file as gui |
1362 | +from ubuntuone.controlpanel.gui.qt.tests import ( |
1363 | + BaseTestCase, |
1364 | + FakeDesktopService, |
1365 | +) |
1366 | + |
1367 | +# Access to a protected member |
1368 | +# Instance of 'ControlBackend' has no '_called' member |
1369 | +# pylint: disable=W0212, E1103 |
1370 | + |
1371 | + |
1372 | +class ShareFileWidgetTestCase(BaseTestCase): |
1373 | + """Test the ShareFileWidget class.""" |
1374 | + |
1375 | + innerclass_ui = gui.share_file_ui |
1376 | + innerclass_name = "Ui_Form" |
1377 | + class_ui = gui.ShareFileWidget |
1378 | + file_path = u'/home/ñandú/Ubuntu One/my_file.txt' |
1379 | + kwargs = {'file_path': file_path} |
1380 | + logger = gui.logger |
1381 | + |
1382 | + def test_init(self): |
1383 | + """The share file widget initialization.""" |
1384 | + self.assertEqual(self.ui.file_path, self.file_path) |
1385 | + self.assertEqual(self.ui.ui.lbl_filename.text(), |
1386 | + os.path.basename(self.file_path)) |
1387 | + self.assertEqual(self.ui.ui.lbl_path.text(), self.file_path) |
1388 | + |
1389 | + def test_open_file(self): |
1390 | + """Test that open file is called properly.""" |
1391 | + fake_desktop_service = FakeDesktopService() |
1392 | + self.patch(QtGui, "QDesktopServices", fake_desktop_service) |
1393 | + self.ui.ui.btn_open.click() |
1394 | + |
1395 | + expected = QtCore.QUrl(u'file://%s' % self.file_path) |
1396 | + self.assertEqual(expected, fake_desktop_service.opened_url) |
1397 | + |
1398 | + def test_disable_link(self): |
1399 | + """Test the disable link action.""" |
1400 | + data = [] |
1401 | + |
1402 | + def fake_change_access(path, access): |
1403 | + """Fake change access type callback.""" |
1404 | + data.append(path) |
1405 | + data.append(access) |
1406 | + |
1407 | + self.ui.linkDisabled.connect(self._set_called) |
1408 | + self.patch(self.ui.backend, "change_public_access", |
1409 | + fake_change_access) |
1410 | + self.ui.ui.btn_disable.click() |
1411 | + |
1412 | + expected = [os.path.expanduser(self.file_path), False] |
1413 | + self.assertEqual(data, expected) |
1414 | + self.assertEqual(self._called, ((), {})) |
1415 | |
1416 | === modified file 'ubuntuone/controlpanel/gui/qt/tests/test_share_links.py' |
1417 | --- ubuntuone/controlpanel/gui/qt/tests/test_share_links.py 2012-08-20 18:24:20 +0000 |
1418 | +++ ubuntuone/controlpanel/gui/qt/tests/test_share_links.py 2012-08-29 18:07:21 +0000 |
1419 | @@ -14,15 +14,25 @@ |
1420 | # You should have received a copy of the GNU General Public License along |
1421 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
1422 | |
1423 | -"""Tests for the account tab.""" |
1424 | +"""Tests for the Share Links tab.""" |
1425 | + |
1426 | +import os |
1427 | + |
1428 | +from PyQt4 import QtGui, QtCore |
1429 | |
1430 | from ubuntuone.controlpanel.gui import ( |
1431 | SEARCH_FILES, |
1432 | SHARED_FILES, |
1433 | ) |
1434 | +from ubuntuone.controlpanel.gui.tests import USER_HOME |
1435 | from ubuntuone.controlpanel.gui.qt import share_links as gui |
1436 | -from ubuntuone.controlpanel.gui.qt.tests import BaseTestCase |
1437 | - |
1438 | +from ubuntuone.controlpanel.gui.qt.tests import ( |
1439 | + BaseTestCase, |
1440 | + FakeDesktopService, |
1441 | +) |
1442 | + |
1443 | + |
1444 | +# pylint: disable=W0212 |
1445 | |
1446 | class ShareLinksTestCase(BaseTestCase): |
1447 | """Test the qt control panel.""" |
1448 | @@ -35,3 +45,151 @@ |
1449 | """Check that the strings are properly setted.""" |
1450 | self.assertEqual(self.ui.ui.search_files_lbl.text(), SEARCH_FILES) |
1451 | self.assertEqual(self.ui.ui.shared_group.title(), SHARED_FILES) |
1452 | + self.assertIsInstance(self.ui._enhanced_line, gui.EnhancedLineEdit) |
1453 | + self.assertEqual(self.ui._enhanced_line.btn_operation.text(), '') |
1454 | + self.assertFalse(self.ui._enhanced_line.btn_operation.isVisible()) |
1455 | + |
1456 | + def test_share_file(self): |
1457 | + """Check that the state of the widgets on share_file.""" |
1458 | + path = '/home/user/Ubuntu One/file1.txt' |
1459 | + self.ui.share_file(path) |
1460 | + self.assertTrue(self.ui.is_processing) |
1461 | + widget = self.ui.ui.hbox_share_file.takeAt(0).widget() |
1462 | + self.assertIsInstance(widget, gui.ShareFileWidget) |
1463 | + self.assertEqual(widget.ui.lbl_filename.text(), |
1464 | + os.path.basename(path)) |
1465 | + self.assertEqual(widget.ui.lbl_path.text(), path) |
1466 | + |
1467 | + def test_share_file_actions(self): |
1468 | + """Check the behaviour of share_file buttons.""" |
1469 | + path = '/home/user/Ubuntu One/file1.txt' |
1470 | + self.ui.share_file(path) |
1471 | + widget = self.ui.ui.hbox_share_file.takeAt(0).widget() |
1472 | + self.ui.ui.line_copy_link.setText('link') |
1473 | + self.assertEqual(self.ui.ui.line_copy_link.text(), 'link') |
1474 | + widget.linkDisabled.emit() |
1475 | + self.assertNotEqual(self.ui.ui.line_copy_link.text(), 'link') |
1476 | + |
1477 | + def test_file_shared(self): |
1478 | + """Check the behavior of the widgets after the file is shared.""" |
1479 | + info = {'public_url': 'http://ubuntuone.com/asd123'} |
1480 | + self.ui._file_shared(info) |
1481 | + self.assertEqual(self.ui.ui.line_copy_link.text(), info['public_url']) |
1482 | + self.assertEqual(self.ui.ui.stacked_widget.currentIndex(), 1) |
1483 | + self.assertFalse(self.ui.is_processing) |
1484 | + |
1485 | + def test_open_in_browser(self): |
1486 | + """Test the execution of open_in_browser.""" |
1487 | + fake_desktop_service = FakeDesktopService() |
1488 | + self.patch(QtGui, "QDesktopServices", fake_desktop_service) |
1489 | + url = 'http://ubuntuone.com/asd123' |
1490 | + self.ui.ui.line_copy_link.setText(url) |
1491 | + self.ui._open_in_browser() |
1492 | + expected = QtCore.QUrl(url) |
1493 | + self.assertEqual(expected, fake_desktop_service.opened_url) |
1494 | + |
1495 | + def test_copy_link_from_line(self): |
1496 | + """Test the execution of copy_link_from_line.""" |
1497 | + url = 'http://ubuntuone.com/asd123' |
1498 | + self.ui.ui.line_copy_link.setText(url) |
1499 | + self.ui._copy_link_from_line() |
1500 | + clip = QtGui.QApplication.instance().clipboard() |
1501 | + self.assertEqual(url, clip.text()) |
1502 | + |
1503 | + def test_move_to_main_list(self): |
1504 | + """Test that the stacked widget shows the proper index.""" |
1505 | + self.ui._move_to_main_list() |
1506 | + self.assertEqual(self.ui.ui.stacked_widget.currentIndex(), 0) |
1507 | + |
1508 | + def test_get_public_files(self): |
1509 | + """Test that the proper actions are executed on files requested..""" |
1510 | + self.ui.get_public_files() |
1511 | + self.assertTrue(self.ui.is_processing) |
1512 | + self.assertEqual(self.ui.ui.stacked_widget.currentIndex(), 0) |
1513 | + self.assertEqual(self.ui.home_dir, USER_HOME) |
1514 | + |
1515 | + def test_line_close_btn(self): |
1516 | + """Check that the popup is hidden.""" |
1517 | + self.ui.ui.line_search.popup.show() |
1518 | + self.addCleanup(self.ui.ui.line_search.popup.hide) |
1519 | + self.ui._line_close_btn() |
1520 | + self.assertFalse(self.ui.ui.line_search.popup.isVisible()) |
1521 | + |
1522 | + def test_hide_line_btn_close_hide(self): |
1523 | + """Check the state of the inline button.""" |
1524 | + self.ui._enhanced_line.btn_operation.show() |
1525 | + self.ui.ui.line_search.popup.popupHidden.emit() |
1526 | + self.assertFalse(self.ui._enhanced_line.btn_operation.isVisible()) |
1527 | + |
1528 | + def test_hide_line_btn_close_show(self): |
1529 | + """Check the state of the inline button.""" |
1530 | + self.ui.ui.line_search.popup.popupShown.emit() |
1531 | + self.assertTrue(self.ui._enhanced_line.btn_operation.isVisible()) |
1532 | + |
1533 | + def test_load_public_files(self): |
1534 | + """Test if the list of public files is loaded properly.""" |
1535 | + publicfiles = [ |
1536 | + {'path': '/home/file1', 'public_url': 'http:ubuntuone.com/asd123'}, |
1537 | + {'path': '/home/file2', 'public_url': 'http:ubuntuone.com/qwe456'}, |
1538 | + ] |
1539 | + self.ui._load_public_files(publicfiles) |
1540 | + item = self.ui.ui.tree_shared_files.topLevelItem(0) |
1541 | + self.assertEqual(item.text(0), os.path.basename('/home/file1')) |
1542 | + self.assertEqual(item.toolTip(0), '/home/file1') |
1543 | + label = self.ui.ui.tree_shared_files.itemWidget(item, 1) |
1544 | + link = ('<a href="%s"><span style="font-size: 12px;' |
1545 | + 'color: #dd4814";>%s</span></a>' |
1546 | + % ('http:ubuntuone.com/asd123', 'http:ubuntuone.com/asd123')) |
1547 | + self.assertEqual(link, label.text()) |
1548 | + actions = self.ui.ui.tree_shared_files.itemWidget(item, 2) |
1549 | + self.assertIsInstance(actions, gui.ActionsButtons) |
1550 | + |
1551 | + item = self.ui.ui.tree_shared_files.topLevelItem(1) |
1552 | + self.assertEqual(item.text(0), os.path.basename('/home/file2')) |
1553 | + self.assertEqual(item.toolTip(0), '/home/file2') |
1554 | + label = self.ui.ui.tree_shared_files.itemWidget(item, 1) |
1555 | + link = ('<a href="%s"><span style="font-size: 12px;' |
1556 | + 'color: #dd4814";>%s</span></a>' |
1557 | + % ('http:ubuntuone.com/qwe456', 'http:ubuntuone.com/qwe456')) |
1558 | + self.assertEqual(link, label.text()) |
1559 | + actions = self.ui.ui.tree_shared_files.itemWidget(item, 2) |
1560 | + self.assertIsInstance(actions, gui.ActionsButtons) |
1561 | + |
1562 | + |
1563 | +class ActionsButtonsTestCase(BaseTestCase): |
1564 | + """Test the Actions Buttons.""" |
1565 | + |
1566 | + def test_open(self): |
1567 | + """Test the open method.""" |
1568 | + path = '/home/file1' |
1569 | + link = 'http://ubuntuone.com/asd123' |
1570 | + actions = gui.ActionsButtons(path, link) |
1571 | + fake_desktop_service = FakeDesktopService() |
1572 | + self.patch(QtGui, "QDesktopServices", fake_desktop_service) |
1573 | + actions.open() |
1574 | + file_path = QtCore.QUrl(u'file://%s' % path) |
1575 | + self.assertEqual(file_path, fake_desktop_service.opened_url) |
1576 | + |
1577 | + def test_copy(self): |
1578 | + """Test that the link is copied into the clipboard..""" |
1579 | + path = '/home/file1' |
1580 | + link = 'http://ubuntuone.com/asd123' |
1581 | + actions = gui.ActionsButtons(path, link) |
1582 | + fake_desktop_service = FakeDesktopService() |
1583 | + self.patch(QtGui, "QDesktopServices", fake_desktop_service) |
1584 | + actions.copy() |
1585 | + clip = QtGui.QApplication.instance().clipboard() |
1586 | + self.assertEqual(link, clip.text()) |
1587 | + |
1588 | + |
1589 | +class EnhancedLineEditTestCase(BaseTestCase): |
1590 | + """Test the EnhancedLineEdit.""" |
1591 | + |
1592 | + def test_initialize(self): |
1593 | + """Test initialization.""" |
1594 | + line = QtGui.QLineEdit() |
1595 | + enhanced = gui.EnhancedLineEdit(line, self._set_called, 'text') |
1596 | + self.assertEqual(line.layout().count(), 2) |
1597 | + self.assertFalse(self._called) |
1598 | + enhanced.btn_operation.click() |
1599 | + self.assertEqual(self._called, ((False, ), {})) |
1600 | |
1601 | === added file 'ubuntuone/controlpanel/gui/qt/tests/test_share_links_search.py' |
1602 | --- ubuntuone/controlpanel/gui/qt/tests/test_share_links_search.py 1970-01-01 00:00:00 +0000 |
1603 | +++ ubuntuone/controlpanel/gui/qt/tests/test_share_links_search.py 2012-08-29 18:07:21 +0000 |
1604 | @@ -0,0 +1,302 @@ |
1605 | +# -*- coding: utf-8 -*- |
1606 | + |
1607 | +# Copyright 2012 Canonical Ltd. |
1608 | +# |
1609 | +# This program is free software: you can redistribute it and/or modify it |
1610 | +# under the terms of the GNU General Public License version 3, as published |
1611 | +# by the Free Software Foundation. |
1612 | +# |
1613 | +# This program is distributed in the hope that it will be useful, but |
1614 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
1615 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1616 | +# PURPOSE. See the GNU General Public License for more details. |
1617 | +# |
1618 | +# You should have received a copy of the GNU General Public License along |
1619 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
1620 | + |
1621 | +"""Tests for the Share Links Search.""" |
1622 | + |
1623 | +import os |
1624 | + |
1625 | +from twisted.internet import defer |
1626 | + |
1627 | +from ubuntuone.controlpanel.gui.tests import USER_HOME |
1628 | +from ubuntuone.controlpanel.gui.qt import share_links_search as gui |
1629 | +from ubuntuone.controlpanel.gui.qt.tests import BaseTestCase |
1630 | + |
1631 | + |
1632 | +# pylint: disable=W0212 |
1633 | + |
1634 | +class SearchBoxTestCase(BaseTestCase): |
1635 | + """Test the qt control panel.""" |
1636 | + |
1637 | + class_ui = gui.SearchBox |
1638 | + |
1639 | + @defer.inlineCallbacks |
1640 | + def setUp(self): |
1641 | + yield super(SearchBoxTestCase, self).setUp() |
1642 | + |
1643 | + self.patch(self.ui._thread_explore, "get_folder_info", |
1644 | + self.fake_get_folder_info) |
1645 | + self.patch(self.ui._thread_explore, "start", |
1646 | + lambda *args, **kwargs: self.ui._thread_explore.run()) |
1647 | + self.folder_info = { |
1648 | + 'folder1': [ |
1649 | + os.path.join(USER_HOME, 'ubuntu', 'file1'), |
1650 | + os.path.join(USER_HOME, 'ubuntu', 'file2'), |
1651 | + os.path.join(USER_HOME, 'one', 'file3'), |
1652 | + ], |
1653 | + 'folder2': [ |
1654 | + os.path.join(USER_HOME, 'test', 'asd'), |
1655 | + os.path.join('other_path', 'test', 'qwe'), |
1656 | + os.path.join(USER_HOME, 'blabla', 'iop'), |
1657 | + ] |
1658 | + } |
1659 | + |
1660 | + def fake_get_folder_info(self, folder): |
1661 | + """Fake get_folder_info.""" |
1662 | + return self.folder_info.get(folder, []) |
1663 | + |
1664 | + def test_initialization(self): |
1665 | + """Check that the widget is build properly""" |
1666 | + self.assertEqual(self.ui.home_dir, USER_HOME) |
1667 | + self.assertEqual(self.ui._thread_explore.u1_files, []) |
1668 | + self.assertEqual(self.ui.temp_u1_files, []) |
1669 | + self.assertEqual(self.ui.items_per_page, 0) |
1670 | + self.assertEqual(self.ui.items_step, 20) |
1671 | + self.assertEqual(self.ui.prefix, '') |
1672 | + |
1673 | + def test_key_down_pressed(self): |
1674 | + """Check the proper action are executed on key down pressed.""" |
1675 | + data1 = [{'path': 'folder1'}] |
1676 | + data2 = [{'realpath': 'folder2'}] |
1677 | + self.ui._process_volumes_info([(0, 0, data1), (0, 0, data2)]) |
1678 | + self.ui.popup.list_widget.setCurrentRow(1) |
1679 | + current = self.ui.popup.list_widget.currentRow() |
1680 | + self.ui._key_down_pressed(current) |
1681 | + self.assertEqual(self.ui.popup.list_widget.currentRow(), 2) |
1682 | + |
1683 | + def test_key_down_pressed_load_more_items(self): |
1684 | + """Check the proper action are executed on key down pressed.""" |
1685 | + data = [] |
1686 | + |
1687 | + def fake_fetch_more(filenames): |
1688 | + """Fake fetch_more.""" |
1689 | + data.append(True) |
1690 | + |
1691 | + self.patch(self.ui.popup, "fetch_more", fake_fetch_more) |
1692 | + data1 = [{'path': 'folder1'}] |
1693 | + data2 = [{'realpath': 'folder2'}] |
1694 | + self.ui._process_volumes_info([(0, 0, data1), (0, 0, data2), |
1695 | + (0, 0, data1), (0, 0, data2), (0, 0, data1), (0, 0, data2), |
1696 | + (0, 0, data1), (0, 0, data2), (0, 0, data1), (0, 0, data2), |
1697 | + (0, 0, data1), (0, 0, data2), (0, 0, data1), (0, 0, data2)]) |
1698 | + self.assertEqual(self.ui.popup.list_widget.count(), 20) |
1699 | + self.ui.popup.list_widget.setCurrentRow( |
1700 | + self.ui.popup.list_widget.count() - 5) |
1701 | + current = self.ui.popup.list_widget.currentRow() |
1702 | + self.ui._key_down_pressed(current) |
1703 | + self.assertEqual(data, [True]) |
1704 | + |
1705 | + def test_key_up_pressed(self): |
1706 | + """Check the proper action are executed on key up pressed.""" |
1707 | + data1 = [{'path': 'folder1'}] |
1708 | + data2 = [{'realpath': 'folder2'}] |
1709 | + self.ui._process_volumes_info([(0, 0, data1), (0, 0, data2)]) |
1710 | + self.ui.popup.list_widget.setCurrentRow(1) |
1711 | + current = self.ui.popup.list_widget.currentRow() |
1712 | + self.ui._key_up_pressed(current) |
1713 | + self.assertEqual(self.ui.popup.list_widget.currentRow(), 0) |
1714 | + |
1715 | + def test_key_up_pressed_stay_in_0(self): |
1716 | + """Check the proper action are executed on key up pressed.""" |
1717 | + data1 = [{'path': 'folder1'}] |
1718 | + data2 = [{'realpath': 'folder2'}] |
1719 | + self.ui._process_volumes_info([(0, 0, data1), (0, 0, data2)]) |
1720 | + self.ui.popup.list_widget.setCurrentRow(0) |
1721 | + current = self.ui.popup.list_widget.currentRow() |
1722 | + self.assertEqual(self.ui.popup.list_widget.currentRow(), 0) |
1723 | + self.ui._key_up_pressed(current) |
1724 | + self.assertEqual(self.ui.popup.list_widget.currentRow(), 0) |
1725 | + |
1726 | + def test_key_return_pressed(self): |
1727 | + """Check the proper action are executed on key return pressed.""" |
1728 | + data1 = [{'path': 'folder1'}] |
1729 | + data2 = [{'realpath': 'folder2'}] |
1730 | + self.ui._process_volumes_info([(0, 0, data1), (0, 0, data2)]) |
1731 | + self.ui.popup.list_widget.setCurrentRow(1) |
1732 | + current = self.ui.popup.list_widget.currentRow() |
1733 | + self.ui._key_return_pressed(current) |
1734 | + |
1735 | + def test_key_space_pressed(self): |
1736 | + """Check the proper action are executed on key space pressed.""" |
1737 | + data = [] |
1738 | + |
1739 | + def fake_set_text(text): |
1740 | + """fake setText.""" |
1741 | + data.append(text) |
1742 | + |
1743 | + self.patch(self.ui, "setText", fake_set_text) |
1744 | + data1 = [{'path': 'folder1'}] |
1745 | + data2 = [{'realpath': 'folder2'}] |
1746 | + self.ui._process_volumes_info([(0, 0, data1), (0, 0, data2)]) |
1747 | + self.ui.popup.list_widget.setCurrentRow(1) |
1748 | + |
1749 | + self.ui._key_space_pressed() |
1750 | + expected = ['iop'] |
1751 | + self.assertEqual(expected, data) |
1752 | + |
1753 | + def test_process_volumes_info(self): |
1754 | + """Check that _process_volumes_info obtain the proper info.""" |
1755 | + data1 = [{'path': 'folder1'}] |
1756 | + data2 = [{'realpath': 'folder2'}] |
1757 | + self.ui._process_volumes_info([(0, 0, data1), (0, 0, data2)]) |
1758 | + expected = [ |
1759 | + 'other_path/test/qwe', |
1760 | + '~/blabla/iop', |
1761 | + '~/one/file3', |
1762 | + '~/test/asd', |
1763 | + '~/ubuntu/file1', |
1764 | + '~/ubuntu/file2'] |
1765 | + self.assertEqual(self.ui._thread_explore.u1_files, expected) |
1766 | + self.assertEqual(self.ui.popup.list_widget.count(), 6) |
1767 | + |
1768 | + def test_filter(self): |
1769 | + """Check the results of the filter.""" |
1770 | + # This tests the behavior of: |
1771 | + # filter |
1772 | + # _show_filter |
1773 | + # _get_filtered_list |
1774 | + self.patch(self.ui.popup, "isVisible", lambda: True) |
1775 | + data1 = [{'path': 'folder1'}] |
1776 | + data2 = [{'realpath': 'folder2'}] |
1777 | + self.ui._process_volumes_info([(0, 0, data1), (0, 0, data2)]) |
1778 | + self.ui.filter('p') |
1779 | + expected = ['~/blabla/iop'] |
1780 | + self.assertEqual(expected, self.ui.temp_u1_files) |
1781 | + |
1782 | + self.ui.filter('i') |
1783 | + expected = [ |
1784 | + '~/blabla/iop', |
1785 | + '~/one/file3', |
1786 | + '~/ubuntu/file1', |
1787 | + '~/ubuntu/file2'] |
1788 | + self.assertEqual(expected, self.ui.temp_u1_files) |
1789 | + |
1790 | + def test_set_selected_item(self): |
1791 | + """Check the notification of the selected item.""" |
1792 | + self.ui.itemSelected.connect(self._set_called) |
1793 | + self.patch(self.ui.popup, "isVisible", lambda: True) |
1794 | + data1 = [{'path': 'folder1'}] |
1795 | + data2 = [{'realpath': 'folder2'}] |
1796 | + self.ui._process_volumes_info([(0, 0, data1), (0, 0, data2)]) |
1797 | + self.ui.popup.list_widget.setCurrentRow(0) |
1798 | + item = self.ui.popup.list_widget.currentItem() |
1799 | + self.ui._set_selected_item(item) |
1800 | + self.assertEqual(self._called, ((u'other_path/test/qwe',), {})) |
1801 | + self.assertEqual(self.ui.text(), '') |
1802 | + |
1803 | + |
1804 | +class FileItemTestCase(BaseTestCase): |
1805 | + """Test the File Item.""" |
1806 | + |
1807 | + class_ui = gui.FileItem |
1808 | + file_path = '/home/tester/ubuntu/file1.txt' |
1809 | + kwargs = {'file_path': file_path} |
1810 | + |
1811 | + def test_default(self): |
1812 | + """Check the default style of the item""" |
1813 | + name = os.path.basename(self.file_path) |
1814 | + style = self.ui.text_style.format(name, self.file_path, |
1815 | + '#333333', 'grey') |
1816 | + self.assertEqual(self.ui.text(), style) |
1817 | + |
1818 | + def test_selected(self): |
1819 | + """Check the default style of the item""" |
1820 | + self.ui.set_selected() |
1821 | + name = os.path.basename(self.file_path) |
1822 | + style = self.ui.text_style.format(name, self.file_path, |
1823 | + 'white', 'white') |
1824 | + self.assertEqual(self.ui.text(), style) |
1825 | + |
1826 | + def test_not_selected(self): |
1827 | + """Check the default style of the item""" |
1828 | + self.ui.set_not_selected() |
1829 | + name = os.path.basename(self.file_path) |
1830 | + style = self.ui.text_style.format(name, self.file_path, |
1831 | + '#333333', 'grey') |
1832 | + self.assertEqual(self.ui.text(), style) |
1833 | + |
1834 | + |
1835 | +class FilesPopupTestCase(BaseTestCase): |
1836 | + |
1837 | + """FilesPopup tests.""" |
1838 | + |
1839 | + class_ui = gui.FilesPopup |
1840 | + text_style = (u"<span style='color: {2};'>{0}</span><br>" |
1841 | + "<span style='font-size: 13px; color: {3};'>({1})</span>") |
1842 | + |
1843 | + def test_load_items(self): |
1844 | + """Tests that the items are loaded properly.""" |
1845 | + items = [ |
1846 | + '/home/tester/file1', |
1847 | + '/home/tester/file2', |
1848 | + '/home/tester/file3', |
1849 | + ] |
1850 | + |
1851 | + self.assertEqual(self.ui.list_widget.count(), 0) |
1852 | + self.ui.load_items(items) |
1853 | + self.assertEqual(self.ui.list_widget.count(), 3) |
1854 | + # Check that we erase the list on reload |
1855 | + self.ui.load_items(items) |
1856 | + self.assertEqual(self.ui.list_widget.count(), 3) |
1857 | + |
1858 | + def test_fetch_more(self): |
1859 | + """Tests that the items are loaded properly.""" |
1860 | + items = [ |
1861 | + '/home/tester/file1', |
1862 | + '/home/tester/file2', |
1863 | + '/home/tester/file3', |
1864 | + ] |
1865 | + |
1866 | + self.assertEqual(self.ui.list_widget.count(), 0) |
1867 | + self.ui.load_items(items) |
1868 | + self.assertEqual(self.ui.list_widget.count(), 3) |
1869 | + self.ui.fetch_more(items) |
1870 | + self.assertEqual(self.ui.list_widget.count(), 6) |
1871 | + |
1872 | + def test_repaint_items(self): |
1873 | + """Check the style of the items change acording to the selection.""" |
1874 | + items = [ |
1875 | + '/home/tester/file1', |
1876 | + '/home/tester/file2', |
1877 | + '/home/tester/file3', |
1878 | + ] |
1879 | + |
1880 | + self.ui.load_items(items) |
1881 | + current = self.ui.list_widget.item(0) |
1882 | + widget = self.ui.list_widget.itemWidget(current) |
1883 | + next_ = self.ui.list_widget.item(1) |
1884 | + widget2 = self.ui.list_widget.itemWidget(next_) |
1885 | + name = os.path.basename('/home/tester/file1') |
1886 | + style = self.text_style.format(name, '/home/tester/file1', |
1887 | + 'white', 'white') |
1888 | + name2 = os.path.basename('/home/tester/file2') |
1889 | + style2 = self.text_style.format(name2, '/home/tester/file2', |
1890 | + '#333333', 'grey') |
1891 | + self.assertEqual(widget.text(), style) |
1892 | + self.assertEqual(widget2.text(), style2) |
1893 | + |
1894 | + self.ui.list_widget.setCurrentRow(1) |
1895 | + current = self.ui.list_widget.item(1) |
1896 | + widget = self.ui.list_widget.itemWidget(current) |
1897 | + previous = self.ui.list_widget.item(0) |
1898 | + widget2 = self.ui.list_widget.itemWidget(previous) |
1899 | + name = os.path.basename('/home/tester/file2') |
1900 | + style = self.text_style.format(name, '/home/tester/file2', |
1901 | + 'white', 'white') |
1902 | + name2 = os.path.basename('/home/tester/file1') |
1903 | + style2 = self.text_style.format(name2, '/home/tester/file1', |
1904 | + '#333333', 'grey') |
1905 | + self.assertEqual(widget.text(), style) |
1906 | + self.assertEqual(widget2.text(), style2) |
1907 | |
1908 | === modified file 'ubuntuone/controlpanel/gui/qt/tests/test_systray.py' |
1909 | --- ubuntuone/controlpanel/gui/qt/tests/test_systray.py 2012-08-20 14:09:45 +0000 |
1910 | +++ ubuntuone/controlpanel/gui/qt/tests/test_systray.py 2012-08-29 18:07:21 +0000 |
1911 | @@ -31,7 +31,10 @@ |
1912 | UPLOADING, |
1913 | ) |
1914 | from ubuntuone.controlpanel.gui.qt import systray |
1915 | -from ubuntuone.controlpanel.gui.qt.tests import BaseTestCase |
1916 | +from ubuntuone.controlpanel.gui.qt.tests import ( |
1917 | + BaseTestCase, |
1918 | + FakeDesktopService, |
1919 | +) |
1920 | from ubuntuone.controlpanel.tests import ROOT_PATH |
1921 | |
1922 | |
1923 | @@ -59,19 +62,6 @@ |
1924 | super(FakeMainWindow, self).__init__() |
1925 | |
1926 | |
1927 | -class FakeDesktopService(object): |
1928 | - |
1929 | - """Fake QDesktopService.""" |
1930 | - |
1931 | - data = {} |
1932 | - |
1933 | - @classmethod |
1934 | - def openUrl(cls, url): |
1935 | - """Fake openUrl.""" |
1936 | - FakeDesktopService.data['cls'] = cls |
1937 | - FakeDesktopService.data['url'] = url |
1938 | - |
1939 | - |
1940 | class SystrayTestCase(BaseTestCase): |
1941 | |
1942 | """Test the notification area icon.""" |
1943 | @@ -85,7 +75,8 @@ |
1944 | self.patch(systray.TrayIcon, "startTimer", lambda s, x: None) |
1945 | self.patch(systray.TransfersMenu, "startTimer", lambda s, x: None) |
1946 | yield super(SystrayTestCase, self).setUp() |
1947 | - self.patch(QtGui, "QDesktopServices", FakeDesktopService) |
1948 | + self.fake_desktop_service = FakeDesktopService() |
1949 | + self.patch(QtGui, "QDesktopServices", self.fake_desktop_service) |
1950 | |
1951 | def assert_status_correct(self, status_bd, status_ui, action, |
1952 | callback=None): |
1953 | @@ -278,30 +269,26 @@ |
1954 | def test_open_u1_folder_action(self): |
1955 | """Test open_u1_folder_action.""" |
1956 | self.ui.open_u1_folder.trigger() |
1957 | - self.assertEqual(FakeDesktopService.data['cls'], FakeDesktopService) |
1958 | expected_url = QtCore.QUrl(u'file://%s' % ROOT_PATH) |
1959 | - self.assertEqual(FakeDesktopService.data['url'], expected_url) |
1960 | + self.assertEqual(self.fake_desktop_service.opened_url, expected_url) |
1961 | |
1962 | def test_get_more_storage_action(self): |
1963 | """Test get_more_storage.""" |
1964 | self.ui.get_more_storage.trigger() |
1965 | - self.assertEqual(FakeDesktopService.data['cls'], FakeDesktopService) |
1966 | expected_url = QtCore.QUrl(systray.GET_STORAGE_LINK) |
1967 | - self.assertEqual(FakeDesktopService.data['url'], expected_url) |
1968 | + self.assertEqual(self.fake_desktop_service.opened_url, expected_url) |
1969 | |
1970 | def test_go_to_web_action(self): |
1971 | """Test go_to_web.""" |
1972 | self.ui.go_to_web.trigger() |
1973 | - self.assertEqual(FakeDesktopService.data['cls'], FakeDesktopService) |
1974 | expected_url = QtCore.QUrl(systray.DASHBOARD) |
1975 | - self.assertEqual(FakeDesktopService.data['url'], expected_url) |
1976 | + self.assertEqual(self.fake_desktop_service.opened_url, expected_url) |
1977 | |
1978 | def test_get_help_action(self): |
1979 | """Test get_help_online.""" |
1980 | self.ui.get_help_online.trigger() |
1981 | - self.assertEqual(FakeDesktopService.data['cls'], FakeDesktopService) |
1982 | expected_url = QtCore.QUrl(systray.GET_SUPPORT_LINK) |
1983 | - self.assertEqual(FakeDesktopService.data['url'], expected_url) |
1984 | + self.assertEqual(self.fake_desktop_service.opened_url, expected_url) |
1985 | |
1986 | def test_initialization(self): |
1987 | """Test that everything initializes correctly.""" |
1988 | @@ -353,7 +340,8 @@ |
1989 | self.patch(systray.TrayIcon, "startTimer", lambda s, x: None) |
1990 | self.patch(systray.TransfersMenu, "startTimer", lambda s, x: None) |
1991 | yield super(TransfersMenuTestCase, self).setUp() |
1992 | - self.patch(QtGui, "QDesktopServices", FakeDesktopService) |
1993 | + self.fake_desktop_service = FakeDesktopService() |
1994 | + self.patch(QtGui, "QDesktopServices", self.fake_desktop_service) |
1995 | self.patch(self.ui.transfers._parent.backend, "sync_menu", |
1996 | self.fake_sync_menu) |
1997 | self.recent_transfers = [] |
1998 | @@ -558,7 +546,8 @@ |
1999 | self.patch(systray.TrayIcon, "startTimer", lambda s, x: None) |
2000 | self.patch(systray.TransfersMenu, "startTimer", lambda s, x: None) |
2001 | yield super(SharesTestCase, self).setUp() |
2002 | - self.patch(QtGui, "QDesktopServices", FakeDesktopService) |
2003 | + self.fake_desktop_service = FakeDesktopService() |
2004 | + self.patch(QtGui, "QDesktopServices", self.fake_desktop_service) |
2005 | self.patch(self.ui.backend, "get_shares", self.fake_get_backend) |
2006 | self._shares_info = [] |
2007 | |
2008 | @@ -596,4 +585,4 @@ |
2009 | share_action = actions[7] |
2010 | share_action.trigger() |
2011 | expected = QtCore.QUrl(systray.ACCEPT_SHARES % volume_id) |
2012 | - self.assertEqual(FakeDesktopService.data['url'], expected) |
2013 | + self.assertEqual(self.fake_desktop_service.opened_url, expected) |
2014 | |
2015 | === modified file 'ubuntuone/controlpanel/sd_client/__init__.py' |
2016 | --- ubuntuone/controlpanel/sd_client/__init__.py 2012-08-08 18:44:57 +0000 |
2017 | +++ ubuntuone/controlpanel/sd_client/__init__.py 2012-08-29 18:07:21 +0000 |
2018 | @@ -209,3 +209,23 @@ |
2019 | def sync_menu(self): |
2020 | """Get the sync menu data from syncdaemon.""" |
2021 | return self.proxy.sync_menu() |
2022 | + |
2023 | + def get_public_files(self): |
2024 | + """Trigger an action to get the list of public files.""" |
2025 | + return self.proxy.get_public_files() |
2026 | + |
2027 | + def set_public_files_list_handler(self, handler): |
2028 | + """Set the public files list handler.""" |
2029 | + return self.proxy.connect_signal('PublicFilesList', handler) |
2030 | + |
2031 | + def change_public_access(self, path, is_public): |
2032 | + """Change the access type of the file.""" |
2033 | + return self.proxy.change_public_access(path, is_public) |
2034 | + |
2035 | + def set_public_access_changed_handler(self, handler): |
2036 | + """Set the status handler function.""" |
2037 | + return self.proxy.connect_signal('PublicAccessChanged', handler) |
2038 | + |
2039 | + def set_public_access_change_error_handler(self, handler): |
2040 | + """Set the status handler function.""" |
2041 | + return self.proxy.connect_signal('PublicAccessChangeError', handler) |
2042 | |
2043 | === modified file 'ubuntuone/controlpanel/tests/test_backend.py' |
2044 | --- ubuntuone/controlpanel/tests/test_backend.py 2012-08-08 18:36:45 +0000 |
2045 | +++ ubuntuone/controlpanel/tests/test_backend.py 2012-08-29 18:07:21 +0000 |
2046 | @@ -161,6 +161,8 @@ |
2047 | 'is_error': '', 'is_connected': 'True', 'is_online': '', |
2048 | } |
2049 | self.status_changed_handler = None |
2050 | + self.public_files_list_handler = None |
2051 | + self.public_access_changed_handler = None |
2052 | self.subscribed_folders = [] |
2053 | self.subscribed_shares = [] |
2054 | self.actions = [] |
2055 | @@ -168,6 +170,13 @@ |
2056 | self.folders = [] |
2057 | self.volumes_refreshed = False |
2058 | self.menu_data = {'recent-transfers': (), 'uploading': ()} |
2059 | + self.publicfiles = [ |
2060 | + {'path': '/home/file1', 'public_url': 'http:ubuntuone.com/asd123'}, |
2061 | + {'path': '/home/file2', 'public_url': 'http:ubuntuone.com/qwe456'}, |
2062 | + ] |
2063 | + self.public_access_info = { |
2064 | + 'public_url': 'http:ubuntuone.com/zxc789' |
2065 | + } |
2066 | |
2067 | def get_throttling_limits(self): |
2068 | """Return the sample speed limits.""" |
2069 | @@ -331,6 +340,24 @@ |
2070 | """Return the sync menu data.""" |
2071 | return self.menu_data |
2072 | |
2073 | + def get_public_files(self): |
2074 | + """Trigger the action to get the public files.""" |
2075 | + if self.public_files_list_handler is not None: |
2076 | + self.public_files_list_handler(self.publicfiles) |
2077 | + |
2078 | + def set_public_files_list_handler(self, handler): |
2079 | + """Return the handler to be called for the public files list.""" |
2080 | + self.public_files_list_handler = handler |
2081 | + |
2082 | + def change_public_access(self, path, is_public): |
2083 | + """Change the type access of a file.""" |
2084 | + if self.public_access_changed_handler is not None and is_public: |
2085 | + self.public_access_changed_handler(self.public_access_info) |
2086 | + |
2087 | + def set_public_access_changed_handler(self, handler): |
2088 | + """Return the handler to be called when a access type change.""" |
2089 | + self.public_access_changed_handler = handler |
2090 | + |
2091 | |
2092 | class MockReplicationClient(CallRecorder): |
2093 | """A mock replication_client module.""" |
2094 | @@ -1709,3 +1736,40 @@ |
2095 | result = yield self.be.sync_menu() |
2096 | expected = {'recent-transfers': (), 'uploading': ()} |
2097 | self.assertEqual(result, expected) |
2098 | + |
2099 | + @inlineCallbacks |
2100 | + def test_get_public_files(self): |
2101 | + """Check that we get list of public files.""" |
2102 | + data = [] |
2103 | + |
2104 | + def get_public_files_handler(publicfiles): |
2105 | + """Callback for get_public_files.""" |
2106 | + data.append(publicfiles) |
2107 | + |
2108 | + self.be.set_public_files_list_handler(get_public_files_handler) |
2109 | + yield self.be.get_public_files() |
2110 | + expected = [[{'path': '/home/file1', |
2111 | + 'public_url': 'http:ubuntuone.com/asd123'}, |
2112 | + {'path': '/home/file2', |
2113 | + 'public_url': 'http:ubuntuone.com/qwe456'}]] |
2114 | + self.assertEqual(expected, data) |
2115 | + |
2116 | + @inlineCallbacks |
2117 | + def test_get_shares(self): |
2118 | + """Check that we get the list of shares.""" |
2119 | + result = yield self.be.get_shares() |
2120 | + self.assertEqual(result, []) |
2121 | + |
2122 | + @inlineCallbacks |
2123 | + def test_change_public_access_set_public(self): |
2124 | + """Check that we get a notification when the access type change.""" |
2125 | + data = [] |
2126 | + |
2127 | + def public_access_change_handler(info): |
2128 | + """Callback for get_public_files.""" |
2129 | + data.append(info) |
2130 | + |
2131 | + self.be.set_public_access_changed_handler(public_access_change_handler) |
2132 | + yield self.be.change_public_access('file1', True) |
2133 | + expected = {'public_url': 'http:ubuntuone.com/zxc789'} |
2134 | + self.assertEqual([expected], data) |
2135 | |
2136 | === modified file 'ubuntuone/controlpanel/tests/test_sd_client.py' |
2137 | --- ubuntuone/controlpanel/tests/test_sd_client.py 2012-03-29 21:37:22 +0000 |
2138 | +++ ubuntuone/controlpanel/tests/test_sd_client.py 2012-08-29 18:07:21 +0000 |
2139 | @@ -746,3 +746,31 @@ |
2140 | """Handle error when retrieving current syncdaemon status.""" |
2141 | self.patch(self.sd.proxy, 'get_status', self.fake_fail) |
2142 | yield self.assertFailure(self.sd.get_current_status(), CustomError) |
2143 | + |
2144 | + |
2145 | +class PublicFilesTestCase(BaseTestCase): |
2146 | + """Test for the public files syncdaemon client methods.""" |
2147 | + |
2148 | + @inlineCallbacks |
2149 | + def test_set_public_files_list_handler(self): |
2150 | + """Connect a handler to the public files signal.""" |
2151 | + sample_handler = object() |
2152 | + yield self.sd.set_public_files_list_handler(sample_handler) |
2153 | + self.assertEqual(sample_handler, |
2154 | + self.sd.proxy.called['PublicFilesList']) |
2155 | + |
2156 | + @inlineCallbacks |
2157 | + def test_set_public_access_changed_handler(self): |
2158 | + """Connect a handler to the public access changed signal.""" |
2159 | + sample_handler = object() |
2160 | + yield self.sd.set_public_access_changed_handler(sample_handler) |
2161 | + self.assertEqual(sample_handler, |
2162 | + self.sd.proxy.called['PublicAccessChanged']) |
2163 | + |
2164 | + @inlineCallbacks |
2165 | + def test_set_public_access_change_error_handler(self): |
2166 | + """Connect a handler to the public access change error signal.""" |
2167 | + sample_handler = object() |
2168 | + yield self.sd.set_public_access_change_error_handler(sample_handler) |
2169 | + self.assertEqual(sample_handler, |
2170 | + self.sd.proxy.called['PublicAccessChangeError']) |
Looks just like trunk.