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