Merge lp:~nataliabidart/ubuntu/natty/ubuntuone-control-panel/ubuntuone-control-panel-0.9.6 into lp:ubuntu/natty/ubuntuone-control-panel
- Natty (11.04)
- ubuntuone-control-panel-0.9.6
- Merge into natty
Proposed by
Natalia Bidart
Status: | Merged |
---|---|
Merged at revision: | 21 |
Proposed branch: | lp:~nataliabidart/ubuntu/natty/ubuntuone-control-panel/ubuntuone-control-panel-0.9.6 |
Merge into: | lp:ubuntu/natty/ubuntuone-control-panel |
Diff against target: |
590 lines (+250/-37) 12 files modified
PKG-INFO (+1/-1) debian/changelog (+20/-0) debian/control (+6/-6) setup.py (+1/-1) ubuntuone/controlpanel/backend.py (+25/-8) ubuntuone/controlpanel/gtk/gui.py (+24/-6) ubuntuone/controlpanel/gtk/tests/__init__.py (+11/-2) ubuntuone/controlpanel/gtk/tests/test_gui.py (+61/-1) ubuntuone/controlpanel/gtk/tests/test_gui_basic.py (+1/-1) ubuntuone/controlpanel/gtk/tests/test_widgets.py (+8/-0) ubuntuone/controlpanel/gtk/widgets.py (+2/-0) ubuntuone/controlpanel/tests/test_backend.py (+90/-11) |
To merge this branch: | bzr merge lp:~nataliabidart/ubuntu/natty/ubuntuone-control-panel/ubuntuone-control-panel-0.9.6 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Sponsors | Pending | ||
Review via email: mp+57347@code.launchpad.net |
Commit message
Description of the change
* New upstream release.
[ Natalia B. Bidart <email address hidden> ]
- Free bytes will not be displayed in the UI for read-only shares.
Also, backend now handles quota info not available for the root folder
(LP: #726580).
- Setting the unity's urgent prop only if available (LP: #755185).
- Made panel title selectable. Tab messages are now also selectable
(LP: #757543).
- Highlight with red and bold when free space available is very little
(either in own volumes or shares) (LP: #753989).
* debian/control:
- bump depends versions for ubuntuone-client (>= 1.6.0) and
ubuntu-
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'PKG-INFO' | |||
2 | --- PKG-INFO 2011-04-08 16:07:22 +0000 | |||
3 | +++ PKG-INFO 2011-04-12 16:04:35 +0000 | |||
4 | @@ -1,6 +1,6 @@ | |||
5 | 1 | Metadata-Version: 1.1 | 1 | Metadata-Version: 1.1 |
6 | 2 | Name: ubuntuone-control-panel | 2 | Name: ubuntuone-control-panel |
8 | 3 | Version: 0.9.5 | 3 | Version: 0.9.6 |
9 | 4 | Summary: Ubuntu One Control Panel | 4 | Summary: Ubuntu One Control Panel |
10 | 5 | Home-page: https://launchpad.net/ubuntuone-control-panel | 5 | Home-page: https://launchpad.net/ubuntuone-control-panel |
11 | 6 | Author: Natalia Bidart | 6 | Author: Natalia Bidart |
12 | 7 | 7 | ||
13 | === modified file 'debian/changelog' | |||
14 | --- debian/changelog 2011-04-08 20:23:32 +0000 | |||
15 | +++ debian/changelog 2011-04-12 16:04:35 +0000 | |||
16 | @@ -1,3 +1,23 @@ | |||
17 | 1 | ubuntuone-control-panel (0.9.6-0ubuntu1) UNRELEASED; urgency=low | ||
18 | 2 | |||
19 | 3 | * New upstream release. | ||
20 | 4 | |||
21 | 5 | [ Natalia B. Bidart <natalia.bidart@canonical.com> ] | ||
22 | 6 | - Free bytes will not be displayed in the UI for read-only shares. | ||
23 | 7 | Also, backend now handles quota info not available for the root folder | ||
24 | 8 | (LP: #726580). | ||
25 | 9 | - Setting the unity's urgent prop only if available (LP: #755185). | ||
26 | 10 | - Made panel title selectable. Tab messages are now also selectable | ||
27 | 11 | (LP: #757543). | ||
28 | 12 | - Highlight with red and bold when free space available is very little | ||
29 | 13 | (either in own volumes or shares) (LP: #753989). | ||
30 | 14 | |||
31 | 15 | * debian/control: | ||
32 | 16 | - bump depends versions for ubuntuone-client (>= 1.6.0) and | ||
33 | 17 | ubuntu-sso-client (>= 1.2.0). | ||
34 | 18 | |||
35 | 19 | -- Natalia Bidart (nessita) <nataliabidart@gmail.com> Tue, 12 Apr 2011 12:11:11 -0300 | ||
36 | 20 | |||
37 | 1 | ubuntuone-control-panel (0.9.5-0ubuntu1) natty; urgency=low | 21 | ubuntuone-control-panel (0.9.5-0ubuntu1) natty; urgency=low |
38 | 2 | 22 | ||
39 | 3 | * New upstream release: | 23 | * New upstream release: |
40 | 4 | 24 | ||
41 | === modified file 'debian/control' | |||
42 | --- debian/control 2011-03-10 03:09:16 +0000 | |||
43 | +++ debian/control 2011-04-12 16:04:35 +0000 | |||
44 | @@ -17,7 +17,7 @@ | |||
45 | 17 | ${python:Depends}, | 17 | ${python:Depends}, |
46 | 18 | python, | 18 | python, |
47 | 19 | python-ubuntuone-control-panel (= ${binary:Version}), | 19 | python-ubuntuone-control-panel (= ${binary:Version}), |
49 | 20 | ubuntuone-client (>= 1.5.6), | 20 | ubuntuone-client (>= 1.6.0), |
50 | 21 | Recommends: ubuntuone-control-panel-gui | 21 | Recommends: ubuntuone-control-panel-gui |
51 | 22 | Description: Ubuntu One Control Panel | 22 | Description: Ubuntu One Control Panel |
52 | 23 | Desktop application to manage a Ubuntu One account. | 23 | Desktop application to manage a Ubuntu One account. |
53 | @@ -37,8 +37,8 @@ | |||
54 | 37 | python-simplejson, | 37 | python-simplejson, |
55 | 38 | python-twisted-core, | 38 | python-twisted-core, |
56 | 39 | python-twisted-web, | 39 | python-twisted-web, |
59 | 40 | python-ubuntuone-client (>= 1.5.6), | 40 | python-ubuntuone-client (>= 1.6.0), |
60 | 41 | ubuntu-sso-client (>= 1.1.11), | 41 | ubuntu-sso-client (>= 1.2.0), |
61 | 42 | Description: Ubuntu One Control Panel Python Libraries | 42 | Description: Ubuntu One Control Panel Python Libraries |
62 | 43 | Ubuntu One Control Panel provides a Python library to manage an Ubuntu One | 43 | Ubuntu One Control Panel provides a Python library to manage an Ubuntu One |
63 | 44 | account. | 44 | account. |
64 | @@ -54,9 +54,9 @@ | |||
65 | 54 | python-defer, | 54 | python-defer, |
66 | 55 | python-gobject, | 55 | python-gobject, |
67 | 56 | python-gtk2, | 56 | python-gtk2, |
71 | 57 | python-ubuntuone-client (>= 1.5.6), | 57 | python-ubuntuone-client (>= 1.6.0), |
72 | 58 | ubuntu-sso-client (>= 1.1.11), | 58 | ubuntu-sso-client (>= 1.2.0), |
73 | 59 | ubuntuone-client (>= 1.5.6), | 59 | ubuntuone-client (>= 1.6.0), |
74 | 60 | ubuntuone-control-panel (= ${binary:Version}), | 60 | ubuntuone-control-panel (= ${binary:Version}), |
75 | 61 | Provides: ubuntuone-control-panel-gui | 61 | Provides: ubuntuone-control-panel-gui |
76 | 62 | Description: Ubuntu One Control Panel | 62 | Description: Ubuntu One Control Panel |
77 | 63 | 63 | ||
78 | === modified file 'setup.py' | |||
79 | --- setup.py 2011-04-08 16:07:22 +0000 | |||
80 | +++ setup.py 2011-04-12 16:04:35 +0000 | |||
81 | @@ -79,7 +79,7 @@ | |||
82 | 79 | 79 | ||
83 | 80 | DistUtilsExtra.auto.setup( | 80 | DistUtilsExtra.auto.setup( |
84 | 81 | name='ubuntuone-control-panel', | 81 | name='ubuntuone-control-panel', |
86 | 82 | version='0.9.5', | 82 | version='0.9.6', |
87 | 83 | license='GPL v3', | 83 | license='GPL v3', |
88 | 84 | author='Natalia Bidart', | 84 | author='Natalia Bidart', |
89 | 85 | author_email='natalia.bidart@canonical.com', | 85 | author_email='natalia.bidart@canonical.com', |
90 | 86 | 86 | ||
91 | === modified file 'ubuntuone/controlpanel/backend.py' | |||
92 | --- ubuntuone/controlpanel/backend.py 2011-04-08 16:07:22 +0000 | |||
93 | +++ ubuntuone/controlpanel/backend.py 2011-04-12 16:04:35 +0000 | |||
94 | @@ -100,6 +100,7 @@ | |||
95 | 100 | FOLDER_TYPE = u'UDF' | 100 | FOLDER_TYPE = u'UDF' |
96 | 101 | SHARE_TYPE = u'SHARE' | 101 | SHARE_TYPE = u'SHARE' |
97 | 102 | NAME_NOT_SET = u'ENAMENOTSET' | 102 | NAME_NOT_SET = u'ENAMENOTSET' |
98 | 103 | FREE_BYTES_NOT_AVAILABLE = u'EFREEBYTESNOTAVAILABLE' | ||
99 | 103 | STATUS_DISABLED = {MSG_KEY: '', STATUS_KEY: FILE_SYNC_DISABLED} | 104 | STATUS_DISABLED = {MSG_KEY: '', STATUS_KEY: FILE_SYNC_DISABLED} |
100 | 104 | 105 | ||
101 | 105 | def __init__(self, shutdown_func=None): | 106 | def __init__(self, shutdown_func=None): |
102 | @@ -450,14 +451,21 @@ | |||
103 | 450 | """Get the volumes info.""" | 451 | """Get the volumes info.""" |
104 | 451 | self._volumes = {} | 452 | self._volumes = {} |
105 | 452 | 453 | ||
107 | 453 | account = yield self.account_info() | 454 | try: |
108 | 455 | account = yield self.account_info() | ||
109 | 456 | except Exception: # pylint: disable=W0703 | ||
110 | 457 | logger.exception('volumes_info: quota could not be retrieved:') | ||
111 | 458 | free_bytes = self.FREE_BYTES_NOT_AVAILABLE | ||
112 | 459 | else: | ||
113 | 460 | free_bytes = int(account['quota_total']) - \ | ||
114 | 461 | int(account['quota_used']) | ||
115 | 462 | |||
116 | 454 | root_dir = yield dbus_client.get_root_dir() | 463 | root_dir = yield dbus_client.get_root_dir() |
117 | 455 | shares_dir = yield dbus_client.get_shares_dir() | 464 | shares_dir = yield dbus_client.get_shares_dir() |
118 | 456 | shares_dir_link = yield dbus_client.get_shares_dir_link() | 465 | shares_dir_link = yield dbus_client.get_shares_dir_link() |
119 | 457 | folders = yield dbus_client.get_folders() | 466 | folders = yield dbus_client.get_folders() |
120 | 458 | shares = yield dbus_client.get_shares() | 467 | shares = yield dbus_client.get_shares() |
121 | 459 | 468 | ||
122 | 460 | free_bytes = int(account['quota_total']) - int(account['quota_used']) | ||
123 | 461 | root_volume = {u'volume_id': u'', u'path': root_dir, | 469 | root_volume = {u'volume_id': u'', u'path': root_dir, |
124 | 462 | u'subscribed': 'True', u'type': self.ROOT_TYPE} | 470 | u'subscribed': 'True', u'type': self.ROOT_TYPE} |
125 | 463 | self._volumes[u''] = root_volume | 471 | self._volumes[u''] = root_volume |
126 | @@ -465,15 +473,17 @@ | |||
127 | 465 | # group shares by the offering user | 473 | # group shares by the offering user |
128 | 466 | shares_result = defaultdict(list) | 474 | shares_result = defaultdict(list) |
129 | 467 | for share in shares: | 475 | for share in shares: |
130 | 476 | if not bool(share['accepted']): | ||
131 | 477 | continue | ||
132 | 478 | |||
133 | 468 | share[u'type'] = self.SHARE_TYPE | 479 | share[u'type'] = self.SHARE_TYPE |
134 | 469 | 480 | ||
135 | 470 | vid = share['volume_id'] | 481 | vid = share['volume_id'] |
137 | 471 | assert vid not in self._volumes | 482 | if vid in self._volumes: |
138 | 483 | logger.warning('volumes_info: share %r already in the volumes ' | ||
139 | 484 | 'list (%r).', vid, self._volumes[vid]) | ||
140 | 472 | self._volumes[vid] = share | 485 | self._volumes[vid] = share |
141 | 473 | 486 | ||
142 | 474 | if not bool(share['accepted']): | ||
143 | 475 | continue | ||
144 | 476 | |||
145 | 477 | nicer_path = share[u'path'].replace(shares_dir, shares_dir_link) | 487 | nicer_path = share[u'path'].replace(shares_dir, shares_dir_link) |
146 | 478 | share[u'path'] = nicer_path | 488 | share[u'path'] = nicer_path |
147 | 479 | 489 | ||
148 | @@ -488,13 +498,20 @@ | |||
149 | 488 | folder[u'type'] = self.FOLDER_TYPE | 498 | folder[u'type'] = self.FOLDER_TYPE |
150 | 489 | 499 | ||
151 | 490 | vid = folder['volume_id'] | 500 | vid = folder['volume_id'] |
153 | 491 | assert vid not in self._volumes | 501 | if vid in self._volumes: |
154 | 502 | logger.warning('volumes_info: udf %r already in the volumes ' | ||
155 | 503 | 'list (%r).', vid, self._volumes[vid]) | ||
156 | 492 | self._volumes[vid] = folder | 504 | self._volumes[vid] = folder |
157 | 493 | 505 | ||
158 | 494 | result = [(u'', unicode(free_bytes), [root_volume] + folders)] | 506 | result = [(u'', unicode(free_bytes), [root_volume] + folders)] |
159 | 495 | 507 | ||
160 | 496 | for other_username, shares in shares_result.iteritems(): | 508 | for other_username, shares in shares_result.iteritems(): |
162 | 497 | result.append((other_username, shares[0][u'free_bytes'], shares)) | 509 | send_freebytes = any(s['access_level'] == 'Modify' for s in shares) |
163 | 510 | if send_freebytes: | ||
164 | 511 | free_bytes = shares[0][u'free_bytes'] | ||
165 | 512 | else: | ||
166 | 513 | free_bytes = self.FREE_BYTES_NOT_AVAILABLE | ||
167 | 514 | result.append((other_username, free_bytes, shares)) | ||
168 | 498 | 515 | ||
169 | 499 | returnValue(result) | 516 | returnValue(result) |
170 | 500 | 517 | ||
171 | 501 | 518 | ||
172 | === modified file 'ubuntuone/controlpanel/gtk/gui.py' | |||
173 | --- ubuntuone/controlpanel/gtk/gui.py 2011-04-08 16:07:22 +0000 | |||
174 | +++ ubuntuone/controlpanel/gtk/gui.py 2011-04-12 16:04:35 +0000 | |||
175 | @@ -456,7 +456,7 @@ | |||
176 | 456 | 'this computer') | 456 | 'this computer') |
177 | 457 | MY_FOLDERS = _('My folders') | 457 | MY_FOLDERS = _('My folders') |
178 | 458 | ALWAYS_SUBSCRIBED = _('Always in sync!') | 458 | ALWAYS_SUBSCRIBED = _('Always in sync!') |
180 | 459 | FREE_SPACE = _('%(free_space)s available storage') | 459 | FREE_SPACE_TEXT = _('%(free_space)s available storage') |
181 | 460 | NO_VOLUMES = _('No folders to show.') | 460 | NO_VOLUMES = _('No folders to show.') |
182 | 461 | NAME_NOT_SET = _('[unknown user name]') | 461 | NAME_NOT_SET = _('[unknown user name]') |
183 | 462 | CONFIRM_MERGE = _('The contents of your cloud folder will be merged with ' | 462 | CONFIRM_MERGE = _('The contents of your cloud folder will be merged with ' |
184 | @@ -466,13 +466,15 @@ | |||
185 | 466 | MUSIC_REAL_PATH = '~/.ubuntuone/Purchased from Ubuntu One' | 466 | MUSIC_REAL_PATH = '~/.ubuntuone/Purchased from Ubuntu One' |
186 | 467 | 467 | ||
187 | 468 | MAX_COLS = 8 | 468 | MAX_COLS = 8 |
188 | 469 | MIN_SIZE_FULL = 1048576 | ||
189 | 469 | 470 | ||
190 | 470 | CONTACT_ICON_NAME = 'avatar-default' | 471 | CONTACT_ICON_NAME = 'avatar-default' |
191 | 471 | FOLDER_ICON_NAME = 'folder' | 472 | FOLDER_ICON_NAME = 'folder' |
192 | 472 | SHARE_ICON_NAME = 'folder-remote' | 473 | SHARE_ICON_NAME = 'folder-remote' |
193 | 473 | MUSIC_ICON_NAME = 'audio-x-generic' | 474 | MUSIC_ICON_NAME = 'audio-x-generic' |
196 | 474 | ROW_HEADER = '<span font_size="large"><b>%s</b></span> ' \ | 475 | FREE_SPACE = '<span foreground="grey">%s</span>' % FREE_SPACE_TEXT |
197 | 475 | '<span foreground="grey">%s</span>' | 476 | NO_FREE_SPACE = '<span foreground="red"><b>%s</b></span>' % FREE_SPACE_TEXT |
198 | 477 | ROW_HEADER = '<span font_size="large"><b>%s</b></span> %s' | ||
199 | 476 | ROOT = '%s - <span foreground="%s" font_size="small">%s</span>' | 478 | ROOT = '%s - <span foreground="%s" font_size="small">%s</span>' |
200 | 477 | 479 | ||
201 | 478 | def __init__(self, main_window=None): | 480 | def __init__(self, main_window=None): |
202 | @@ -534,12 +536,28 @@ | |||
203 | 534 | else: | 536 | else: |
204 | 535 | name = self.MY_FOLDERS | 537 | name = self.MY_FOLDERS |
205 | 536 | 538 | ||
208 | 537 | free_bytes_args = {'free_space': self.humanize(int(free_bytes))} | 539 | scroll_to_cell = False |
209 | 538 | row = (self.ROW_HEADER % (name, self.FREE_SPACE % free_bytes_args), | 540 | if free_bytes == backend.ControlBackend.FREE_BYTES_NOT_AVAILABLE: |
210 | 541 | free_bytes = '' | ||
211 | 542 | else: | ||
212 | 543 | free_bytes = int(free_bytes) | ||
213 | 544 | if free_bytes < self.MIN_SIZE_FULL: | ||
214 | 545 | free_bytes_str = self.NO_FREE_SPACE | ||
215 | 546 | scroll_to_cell = True | ||
216 | 547 | else: | ||
217 | 548 | free_bytes_str = self.FREE_SPACE | ||
218 | 549 | free_bytes_args = {'free_space': self.humanize(free_bytes)} | ||
219 | 550 | free_bytes = free_bytes_str % free_bytes_args | ||
220 | 551 | |||
221 | 552 | row = (self.ROW_HEADER % (name, free_bytes), | ||
222 | 539 | True, self.CONTACT_ICON_NAME, False, False, | 553 | True, self.CONTACT_ICON_NAME, False, False, |
223 | 540 | gtk.ICON_SIZE_LARGE_TOOLBAR, None, None) | 554 | gtk.ICON_SIZE_LARGE_TOOLBAR, None, None) |
224 | 541 | treeiter = self.volumes_store.append(None, row) | 555 | treeiter = self.volumes_store.append(None, row) |
225 | 542 | 556 | ||
226 | 557 | if scroll_to_cell: | ||
227 | 558 | path = self.volumes_store.get_string_from_iter(treeiter) | ||
228 | 559 | self.volumes_view.scroll_to_cell(path) | ||
229 | 560 | |||
230 | 543 | volumes.sort(key=operator.itemgetter('path')) | 561 | volumes.sort(key=operator.itemgetter('path')) |
231 | 544 | for volume in volumes: | 562 | for volume in volumes: |
232 | 545 | sensitive = True | 563 | sensitive = True |
233 | @@ -1722,7 +1740,7 @@ | |||
234 | 1722 | if not USE_LIBUNITY: | 1740 | if not USE_LIBUNITY: |
235 | 1723 | return | 1741 | return |
236 | 1724 | entry = Unity.LauncherEntry.get_for_desktop_id(U1_DOTDESKTOP) | 1742 | entry = Unity.LauncherEntry.get_for_desktop_id(U1_DOTDESKTOP) |
238 | 1725 | if entry.props.urgent: | 1743 | if getattr(entry.props, 'urgent', False): |
239 | 1726 | self.switch_to('volumes') | 1744 | self.switch_to('volumes') |
240 | 1727 | entry.props.urgent = False | 1745 | entry.props.urgent = False |
241 | 1728 | 1746 | ||
242 | 1729 | 1747 | ||
243 | === modified file 'ubuntuone/controlpanel/gtk/tests/__init__.py' | |||
244 | --- ubuntuone/controlpanel/gtk/tests/__init__.py 2011-04-08 16:07:22 +0000 | |||
245 | +++ ubuntuone/controlpanel/gtk/tests/__init__.py 2011-04-12 16:04:35 +0000 | |||
246 | @@ -68,7 +68,6 @@ | |||
247 | 68 | {u'volume_id': u'1234', u'name': u'do', | 68 | {u'volume_id': u'1234', u'name': u'do', |
248 | 69 | u'path': u'/home/tester/.local/share/ubuntuone/shares/do from Other User', | 69 | u'path': u'/home/tester/.local/share/ubuntuone/shares/do from Other User', |
249 | 70 | u'subscribed': u'', u'type': ControlBackend.SHARE_TYPE}, | 70 | u'subscribed': u'', u'type': ControlBackend.SHARE_TYPE}, |
250 | 71 | |||
251 | 72 | {u'volume_id': u'5678', u'name': u're', | 71 | {u'volume_id': u'5678', u'name': u're', |
252 | 73 | u'path': u'/home/tester/.local/share/ubuntuone/shares/re from Other User', | 72 | u'path': u'/home/tester/.local/share/ubuntuone/shares/re from Other User', |
253 | 74 | u'subscribed': u'True', u'type': ControlBackend.SHARE_TYPE}, | 73 | u'subscribed': u'True', u'type': ControlBackend.SHARE_TYPE}, |
254 | @@ -76,7 +75,17 @@ | |||
255 | 76 | 75 | ||
256 | 77 | FAKE_VOLUMES_INFO = [ | 76 | FAKE_VOLUMES_INFO = [ |
257 | 78 | (u'', u'147852369', [ROOT] + FAKE_FOLDERS_INFO), | 77 | (u'', u'147852369', [ROOT] + FAKE_FOLDERS_INFO), |
259 | 79 | (u'Other User', u'985674', FAKE_SHARES_INFO), | 78 | (u'Other User', gui.VolumesPanel.MIN_SIZE_FULL, FAKE_SHARES_INFO), |
260 | 79 | ] | ||
261 | 80 | |||
262 | 81 | FAKE_VOLUMES_NO_FREE_SPACE_INFO = [ | ||
263 | 82 | (u'', u'500', [ROOT]), | ||
264 | 83 | (u'No free space', u'0', | ||
265 | 84 | [{u'volume_id': u'0', u'name': u'full', u'path': u'full-share', | ||
266 | 85 | u'subscribed': u'', u'type': ControlBackend.SHARE_TYPE}]), | ||
267 | 86 | (u'Almost no free space', gui.VolumesPanel.MIN_SIZE_FULL - 1, | ||
268 | 87 | [{u'volume_id': u'1', u'name': u'almostfull', u'path': u'almost-full', | ||
269 | 88 | u'subscribed': u'', u'type': ControlBackend.SHARE_TYPE}]), | ||
270 | 80 | ] | 89 | ] |
271 | 81 | 90 | ||
272 | 82 | FAKE_DEVICE_INFO = { | 91 | FAKE_DEVICE_INFO = { |
273 | 83 | 92 | ||
274 | === modified file 'ubuntuone/controlpanel/gtk/tests/test_gui.py' | |||
275 | --- ubuntuone/controlpanel/gtk/tests/test_gui.py 2011-04-08 16:07:22 +0000 | |||
276 | +++ ubuntuone/controlpanel/gtk/tests/test_gui.py 2011-04-12 16:04:35 +0000 | |||
277 | @@ -23,7 +23,7 @@ | |||
278 | 23 | from ubuntuone.controlpanel.gtk import gui | 23 | from ubuntuone.controlpanel.gtk import gui |
279 | 24 | from ubuntuone.controlpanel.gtk.tests import (FAKE_ACCOUNT_INFO, | 24 | from ubuntuone.controlpanel.gtk.tests import (FAKE_ACCOUNT_INFO, |
280 | 25 | FAKE_DEVICE_INFO, FAKE_DEVICES_INFO, FAKE_FOLDERS_INFO, | 25 | FAKE_DEVICE_INFO, FAKE_DEVICES_INFO, FAKE_FOLDERS_INFO, |
282 | 26 | FAKE_VOLUMES_INFO, FAKE_REPLICATIONS_INFO, | 26 | FAKE_VOLUMES_INFO, FAKE_VOLUMES_NO_FREE_SPACE_INFO, FAKE_REPLICATIONS_INFO, |
283 | 27 | MUSIC_FOLDER, ROOT, USER_HOME, | 27 | MUSIC_FOLDER, ROOT, USER_HOME, |
284 | 28 | FakedConfirmDialog, | 28 | FakedConfirmDialog, |
285 | 29 | ) | 29 | ) |
286 | @@ -260,6 +260,66 @@ | |||
287 | 260 | 260 | ||
288 | 261 | self.assertEqual(len(self.ui.volumes_store), 0) | 261 | self.assertEqual(len(self.ui.volumes_store), 0) |
289 | 262 | 262 | ||
290 | 263 | def test_on_volumes_info_ready_highlights_little_free_space(self): | ||
291 | 264 | """The free space is red if is zero (or close to 0).""" | ||
292 | 265 | self.ui.on_volumes_info_ready(FAKE_VOLUMES_NO_FREE_SPACE_INFO) | ||
293 | 266 | |||
294 | 267 | treeiter = self.ui.volumes_store.get_iter_root() | ||
295 | 268 | for name, free_bytes, volumes in FAKE_VOLUMES_NO_FREE_SPACE_INFO: | ||
296 | 269 | name = "%s's" % name if name else self.ui.MY_FOLDERS | ||
297 | 270 | free_bytes = self.ui.humanize(int(free_bytes)) | ||
298 | 271 | free_bytes = self.ui.NO_FREE_SPACE % {'free_space': free_bytes} | ||
299 | 272 | |||
300 | 273 | # check parent row | ||
301 | 274 | row = self.ui.volumes_store.get(treeiter, | ||
302 | 275 | *xrange(self.ui.MAX_COLS)) | ||
303 | 276 | |||
304 | 277 | self.assertEqual(row[0], self.ui.ROW_HEADER % (name, free_bytes)) | ||
305 | 278 | |||
306 | 279 | treeiter = self.ui.volumes_store.iter_next(treeiter) | ||
307 | 280 | |||
308 | 281 | if treeiter is not None: | ||
309 | 282 | # skip the empty row | ||
310 | 283 | row = self.ui.volumes_store.get(treeiter, | ||
311 | 284 | *xrange(self.ui.MAX_COLS)) | ||
312 | 285 | self.assertEqual(row, self.ui._empty_row) | ||
313 | 286 | |||
314 | 287 | # grab next non-empty row | ||
315 | 288 | treeiter = self.ui.volumes_store.iter_next(treeiter) | ||
316 | 289 | |||
317 | 290 | def test_on_volumes_info_ready_handles_no_quota_info(self): | ||
318 | 291 | """The lack of free space is handled.""" | ||
319 | 292 | info = [ | ||
320 | 293 | (u'', gui.backend.ControlBackend.FREE_BYTES_NOT_AVAILABLE, [ROOT]), | ||
321 | 294 | (u'No free space available', | ||
322 | 295 | gui.backend.ControlBackend.FREE_BYTES_NOT_AVAILABLE, | ||
323 | 296 | [{u'volume_id': u'0', u'name': u'full', | ||
324 | 297 | u'path': u'full-share', u'subscribed': u'', | ||
325 | 298 | u'type': gui.backend.ControlBackend.SHARE_TYPE}]), | ||
326 | 299 | ] | ||
327 | 300 | self.ui.on_volumes_info_ready(info) | ||
328 | 301 | |||
329 | 302 | treeiter = self.ui.volumes_store.get_iter_root() | ||
330 | 303 | for name, free_bytes, volumes in info: | ||
331 | 304 | name = "%s's" % name if name else self.ui.MY_FOLDERS | ||
332 | 305 | |||
333 | 306 | # check parent row | ||
334 | 307 | row = self.ui.volumes_store.get(treeiter, | ||
335 | 308 | *xrange(self.ui.MAX_COLS)) | ||
336 | 309 | |||
337 | 310 | self.assertEqual(row[0], self.ui.ROW_HEADER % (name, '')) | ||
338 | 311 | |||
339 | 312 | treeiter = self.ui.volumes_store.iter_next(treeiter) | ||
340 | 313 | |||
341 | 314 | if treeiter is not None: | ||
342 | 315 | # skip the empty row | ||
343 | 316 | row = self.ui.volumes_store.get(treeiter, | ||
344 | 317 | *xrange(self.ui.MAX_COLS)) | ||
345 | 318 | self.assertEqual(row, self.ui._empty_row) | ||
346 | 319 | |||
347 | 320 | # grab next non-empty row | ||
348 | 321 | treeiter = self.ui.volumes_store.iter_next(treeiter) | ||
349 | 322 | |||
350 | 263 | def test_on_volumes_info_error(self): | 323 | def test_on_volumes_info_error(self): |
351 | 264 | """The volumes info couldn't be retrieved.""" | 324 | """The volumes info couldn't be retrieved.""" |
352 | 265 | self.ui.on_volumes_info_error() | 325 | self.ui.on_volumes_info_error() |
353 | 266 | 326 | ||
354 | === modified file 'ubuntuone/controlpanel/gtk/tests/test_gui_basic.py' | |||
355 | --- ubuntuone/controlpanel/gtk/tests/test_gui_basic.py 2011-04-08 16:07:22 +0000 | |||
356 | +++ ubuntuone/controlpanel/gtk/tests/test_gui_basic.py 2011-04-12 16:04:35 +0000 | |||
357 | @@ -143,7 +143,7 @@ | |||
358 | 143 | THE_FLEP.urgent = True | 143 | THE_FLEP.urgent = True |
359 | 144 | self.patch(gui.Unity, "LauncherEntry", FakeLauncherEntry) | 144 | self.patch(gui.Unity, "LauncherEntry", FakeLauncherEntry) |
360 | 145 | cp = gui.ControlPanelWindow() | 145 | cp = gui.ControlPanelWindow() |
362 | 146 | cp.emit('focus-in-event', None) | 146 | cp.emit('focus-in-event', gui.gtk.gdk.Event(gui.gtk.gdk.FOCUS_CHANGE)) |
363 | 147 | self.assertEqual( | 147 | self.assertEqual( |
364 | 148 | False, THE_FLEP.urgent, 'remove_urgency should have been called.') | 148 | False, THE_FLEP.urgent, 'remove_urgency should have been called.') |
365 | 149 | 149 | ||
366 | 150 | 150 | ||
367 | === modified file 'ubuntuone/controlpanel/gtk/tests/test_widgets.py' | |||
368 | --- ubuntuone/controlpanel/gtk/tests/test_widgets.py 2011-03-23 16:06:41 +0000 | |||
369 | +++ ubuntuone/controlpanel/gtk/tests/test_widgets.py 2011-04-12 16:04:35 +0000 | |||
370 | @@ -148,6 +148,10 @@ | |||
371 | 148 | actual = widget.loading.spinner.style.fg[widgets.gtk.STATE_NORMAL] | 148 | actual = widget.loading.spinner.style.fg[widgets.gtk.STATE_NORMAL] |
372 | 149 | self.assertEqual(actual, widgets.gtk.gdk.Color(expected)) | 149 | self.assertEqual(actual, widgets.gtk.gdk.Color(expected)) |
373 | 150 | 150 | ||
374 | 151 | def test_selectable(self): | ||
375 | 152 | """The widget is selectable.""" | ||
376 | 153 | self.assertTrue(self.widget.label.get_selectable()) | ||
377 | 154 | |||
378 | 151 | 155 | ||
379 | 152 | class PanelTitleTestCase(TestCase): | 156 | class PanelTitleTestCase(TestCase): |
380 | 153 | """Tets case for a special title for each management panel.""" | 157 | """Tets case for a special title for each management panel.""" |
381 | @@ -186,3 +190,7 @@ | |||
382 | 186 | """The label padding is correct.""" | 190 | """The label padding is correct.""" |
383 | 187 | self.assertEqual(self.widget.get_padding(), | 191 | self.assertEqual(self.widget.get_padding(), |
384 | 188 | widgets.DEFAULT_PADDING) | 192 | widgets.DEFAULT_PADDING) |
385 | 193 | |||
386 | 194 | def test_selectable(self): | ||
387 | 195 | """The widget is selectable.""" | ||
388 | 196 | self.assertTrue(self.widget.get_selectable()) | ||
389 | 189 | 197 | ||
390 | === modified file 'ubuntuone/controlpanel/gtk/widgets.py' | |||
391 | --- ubuntuone/controlpanel/gtk/widgets.py 2011-03-23 16:06:41 +0000 | |||
392 | +++ ubuntuone/controlpanel/gtk/widgets.py 2011-04-12 16:04:35 +0000 | |||
393 | @@ -55,6 +55,7 @@ | |||
394 | 55 | self.loading = Loading(loading_label, fg_color=fg_color) | 55 | self.loading = Loading(loading_label, fg_color=fg_color) |
395 | 56 | 56 | ||
396 | 57 | self.label = gtk.Label() | 57 | self.label = gtk.Label() |
397 | 58 | self.label.set_selectable(True) | ||
398 | 58 | self.label.show() | 59 | self.label.show() |
399 | 59 | if fg_color is not None: | 60 | if fg_color is not None: |
400 | 60 | self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.Color(fg_color)) | 61 | self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.Color(fg_color)) |
401 | @@ -113,6 +114,7 @@ | |||
402 | 113 | self.set_property('xalign', 0.0) | 114 | self.set_property('xalign', 0.0) |
403 | 114 | self.set_line_wrap(True) | 115 | self.set_line_wrap(True) |
404 | 115 | self.set_line_wrap_mode(pango.WRAP_WORD) | 116 | self.set_line_wrap_mode(pango.WRAP_WORD) |
405 | 117 | self.set_selectable(True) | ||
406 | 116 | self.show_all() | 118 | self.show_all() |
407 | 117 | 119 | ||
408 | 118 | 120 | ||
409 | 119 | 121 | ||
410 | === modified file 'ubuntuone/controlpanel/tests/test_backend.py' | |||
411 | --- ubuntuone/controlpanel/tests/test_backend.py 2011-04-08 16:07:22 +0000 | |||
412 | +++ ubuntuone/controlpanel/tests/test_backend.py 2011-04-12 16:04:35 +0000 | |||
413 | @@ -24,7 +24,7 @@ | |||
414 | 24 | import simplejson | 24 | import simplejson |
415 | 25 | 25 | ||
416 | 26 | from twisted.internet import defer | 26 | from twisted.internet import defer |
418 | 27 | from twisted.internet.defer import inlineCallbacks | 27 | from twisted.internet.defer import inlineCallbacks, returnValue |
419 | 28 | from ubuntuone.devtools.handlers import MementoHandler | 28 | from ubuntuone.devtools.handlers import MementoHandler |
420 | 29 | 29 | ||
421 | 30 | from ubuntuone.controlpanel import backend, replication_client | 30 | from ubuntuone.controlpanel import backend, replication_client |
422 | @@ -98,6 +98,8 @@ | |||
423 | 98 | subscribed_folders = [] | 98 | subscribed_folders = [] |
424 | 99 | subscribed_shares = [] | 99 | subscribed_shares = [] |
425 | 100 | actions = [] | 100 | actions = [] |
426 | 101 | shares = [] | ||
427 | 102 | folders = [] | ||
428 | 101 | 103 | ||
429 | 102 | def get_credentials(self): | 104 | def get_credentials(self): |
430 | 103 | """Return the mock credentials.""" | 105 | """Return the mock credentials.""" |
431 | @@ -179,7 +181,7 @@ | |||
432 | 179 | 181 | ||
433 | 180 | def get_folders(self): | 182 | def get_folders(self): |
434 | 181 | """Grab list of folders.""" | 183 | """Grab list of folders.""" |
436 | 182 | return SAMPLE_FOLDERS | 184 | return MockDBusClient.folders |
437 | 183 | 185 | ||
438 | 184 | def subscribe_folder(self, volume_id): | 186 | def subscribe_folder(self, volume_id): |
439 | 185 | """Subcribe to 'volume_id'.""" | 187 | """Subcribe to 'volume_id'.""" |
440 | @@ -191,7 +193,7 @@ | |||
441 | 191 | 193 | ||
442 | 192 | def get_shares(self): | 194 | def get_shares(self): |
443 | 193 | """Grab list of shares.""" | 195 | """Grab list of shares.""" |
445 | 194 | return SAMPLE_SHARES | 196 | return MockDBusClient.shares |
446 | 195 | 197 | ||
447 | 196 | def subscribe_share(self, volume_id): | 198 | def subscribe_share(self, volume_id): |
448 | 197 | """Subcribe to 'volume_id'.""" | 199 | """Subcribe to 'volume_id'.""" |
449 | @@ -563,10 +565,14 @@ | |||
450 | 563 | self.be.wc.results[QUOTA_API] = SAMPLE_QUOTA_JSON | 565 | self.be.wc.results[QUOTA_API] = SAMPLE_QUOTA_JSON |
451 | 564 | 566 | ||
452 | 565 | @inlineCallbacks | 567 | @inlineCallbacks |
457 | 566 | def test_volumes_info(self): | 568 | def expected_volumes(self, sample_shares, sample_folders): |
458 | 567 | """The volumes_info method exercises its callback.""" | 569 | """Get shares and group by sharing user, get folders and free space.""" |
459 | 568 | result = yield self.be.account_info() | 570 | try: |
460 | 569 | free_bytes = int(result['quota_total']) - int(result['quota_used']) | 571 | result = yield self.be.account_info() |
461 | 572 | except Exception: # pylint: disable=W0703 | ||
462 | 573 | free_bytes = self.be.FREE_BYTES_NOT_AVAILABLE | ||
463 | 574 | else: | ||
464 | 575 | free_bytes = int(result['quota_total']) - int(result['quota_used']) | ||
465 | 570 | 576 | ||
466 | 571 | # get root dir info | 577 | # get root dir info |
467 | 572 | root_volume = {u'volume_id': u'', u'path': ROOT_PATH, | 578 | root_volume = {u'volume_id': u'', u'path': ROOT_PATH, |
468 | @@ -574,7 +580,7 @@ | |||
469 | 574 | 580 | ||
470 | 575 | # get shares and group by sharing user | 581 | # get shares and group by sharing user |
471 | 576 | shares = defaultdict(list) | 582 | shares = defaultdict(list) |
473 | 577 | for share in SAMPLE_SHARES: | 583 | for share in sample_shares: |
474 | 578 | # filter out non accepted values | 584 | # filter out non accepted values |
475 | 579 | if not bool(share['accepted']): | 585 | if not bool(share['accepted']): |
476 | 580 | continue | 586 | continue |
477 | @@ -593,15 +599,29 @@ | |||
478 | 593 | shares[username].append(share) | 599 | shares[username].append(share) |
479 | 594 | 600 | ||
480 | 595 | folders = [] | 601 | folders = [] |
482 | 596 | for folder in SAMPLE_FOLDERS: | 602 | for folder in sample_folders: |
483 | 597 | folder = folder.copy() | 603 | folder = folder.copy() |
484 | 598 | folder[u'type'] = self.be.FOLDER_TYPE | 604 | folder[u'type'] = self.be.FOLDER_TYPE |
485 | 599 | folders.append(folder) | 605 | folders.append(folder) |
486 | 600 | 606 | ||
487 | 601 | expected = [(u'', unicode(free_bytes), [root_volume] + folders)] | 607 | expected = [(u'', unicode(free_bytes), [root_volume] + folders)] |
488 | 602 | for other_user, data in shares.iteritems(): | 608 | for other_user, data in shares.iteritems(): |
491 | 603 | expected.append((other_user, data[0][u'free_bytes'], data)) | 609 | send_freebytes = any(d['access_level'] == 'Modify' for d in data) |
492 | 604 | 610 | if send_freebytes: | |
493 | 611 | free_bytes = data[0][u'free_bytes'] | ||
494 | 612 | else: | ||
495 | 613 | free_bytes = self.be.FREE_BYTES_NOT_AVAILABLE | ||
496 | 614 | expected.append((other_user, free_bytes, data)) | ||
497 | 615 | |||
498 | 616 | returnValue(expected) | ||
499 | 617 | |||
500 | 618 | @inlineCallbacks | ||
501 | 619 | def test_volumes_info(self): | ||
502 | 620 | """The volumes_info method exercises its callback.""" | ||
503 | 621 | self.patch(MockDBusClient, 'shares', SAMPLE_SHARES) | ||
504 | 622 | self.patch(MockDBusClient, 'folders', SAMPLE_FOLDERS) | ||
505 | 623 | |||
506 | 624 | expected = yield self.expected_volumes(SAMPLE_SHARES, SAMPLE_FOLDERS) | ||
507 | 605 | result = yield self.be.volumes_info() | 625 | result = yield self.be.volumes_info() |
508 | 606 | self.assertEqual(result, expected) | 626 | self.assertEqual(result, expected) |
509 | 607 | 627 | ||
510 | @@ -614,14 +634,23 @@ | |||
511 | 614 | @inlineCallbacks | 634 | @inlineCallbacks |
512 | 615 | def test_volumes_are_cached(self): | 635 | def test_volumes_are_cached(self): |
513 | 616 | """The volume list is cached.""" | 636 | """The volume list is cached.""" |
514 | 637 | self.patch(MockDBusClient, 'shares', SAMPLE_SHARES) | ||
515 | 638 | self.patch(MockDBusClient, 'folders', SAMPLE_FOLDERS) | ||
516 | 639 | |||
517 | 617 | # get root dir info | 640 | # get root dir info |
518 | 618 | root_volume = {u'volume_id': u'', u'path': ROOT_PATH, | 641 | root_volume = {u'volume_id': u'', u'path': ROOT_PATH, |
519 | 619 | u'subscribed': 'True', u'type': self.be.ROOT_TYPE} | 642 | u'subscribed': 'True', u'type': self.be.ROOT_TYPE} |
520 | 620 | expected = {u'': root_volume} | 643 | expected = {u'': root_volume} |
521 | 621 | for volume in SAMPLE_SHARES + SAMPLE_FOLDERS: | 644 | for volume in SAMPLE_SHARES + SAMPLE_FOLDERS: |
522 | 645 | volume = volume.copy() | ||
523 | 622 | if volume[u'type'] == u'UDF': | 646 | if volume[u'type'] == u'UDF': |
524 | 623 | volume[u'type'] = self.be.FOLDER_TYPE | 647 | volume[u'type'] = self.be.FOLDER_TYPE |
525 | 624 | else: | 648 | else: |
526 | 649 | if not bool(volume[u'accepted']): | ||
527 | 650 | continue | ||
528 | 651 | path = volume[u'path'] | ||
529 | 652 | nicer_path = path.replace(SHARES_PATH, SHARES_PATH_LINK) | ||
530 | 653 | volume[u'path'] = nicer_path | ||
531 | 625 | volume[u'type'] = self.be.SHARE_TYPE | 654 | volume[u'type'] = self.be.SHARE_TYPE |
532 | 626 | 655 | ||
533 | 627 | sid = volume['volume_id'] | 656 | sid = volume['volume_id'] |
534 | @@ -639,6 +668,56 @@ | |||
535 | 639 | yield self.test_volumes_are_cached() | 668 | yield self.test_volumes_are_cached() |
536 | 640 | 669 | ||
537 | 641 | @inlineCallbacks | 670 | @inlineCallbacks |
538 | 671 | def test_volumes_info_no_quota_for_read_onlys(self): | ||
539 | 672 | """The volumes_info does not send qupota info for RO shares.""" | ||
540 | 673 | read_only_shares = [ | ||
541 | 674 | {u'accepted': u'True', | ||
542 | 675 | u'subscribed': u'True', | ||
543 | 676 | u'access_level': u'View', | ||
544 | 677 | u'free_bytes': u'39892622746', | ||
545 | 678 | u'generation': u'2704', | ||
546 | 679 | u'name': u're', | ||
547 | 680 | u'node_id': u'c483f419-ed28-490a-825d-a8c074e2d795', | ||
548 | 681 | u'other_username': u'otheruser', | ||
549 | 682 | u'other_visible_name': u'Other User', | ||
550 | 683 | u'path': SHARES_PATH + u'/re from Other User', | ||
551 | 684 | u'type': u'Share', | ||
552 | 685 | u'volume_id': u'4a1b263b-a2b3-4f66-9e66-4cd18050810d'}, | ||
553 | 686 | {u'accepted': u'True', | ||
554 | 687 | u'subscribed': u'True', | ||
555 | 688 | u'access_level': u'View', | ||
556 | 689 | u'free_bytes': u'39892622746', | ||
557 | 690 | u'generation': u'2704', | ||
558 | 691 | u'name': u'do', | ||
559 | 692 | u'node_id': u'84544ea4-aefe-4f91-9bb9-ed7b0a805baf', | ||
560 | 693 | u'other_username': u'otheruser', | ||
561 | 694 | u'other_visible_name': u'Other User', | ||
562 | 695 | u'path': SHARES_PATH + u'/do from Other User', | ||
563 | 696 | u'type': u'Share', | ||
564 | 697 | u'volume_id': u'7d130dfe-98b2-4bd5-8708-9eeba9838ac0'}, | ||
565 | 698 | ] | ||
566 | 699 | |||
567 | 700 | self.patch(MockDBusClient, 'shares', read_only_shares) | ||
568 | 701 | self.patch(MockDBusClient, 'folders', SAMPLE_FOLDERS) | ||
569 | 702 | |||
570 | 703 | expected = yield self.expected_volumes(read_only_shares, | ||
571 | 704 | SAMPLE_FOLDERS) | ||
572 | 705 | result = yield self.be.volumes_info() | ||
573 | 706 | self.assertEqual(result, expected) | ||
574 | 707 | |||
575 | 708 | @inlineCallbacks | ||
576 | 709 | def test_volumes_info_no_quota_for_root(self): | ||
577 | 710 | """The volumes_info returns info even if quota call fails.""" | ||
578 | 711 | # pylint: disable=E1101 | ||
579 | 712 | self.be.wc.failure = 500 | ||
580 | 713 | self.patch(MockDBusClient, 'shares', SAMPLE_SHARES) | ||
581 | 714 | self.patch(MockDBusClient, 'folders', SAMPLE_FOLDERS) | ||
582 | 715 | |||
583 | 716 | expected = yield self.expected_volumes(SAMPLE_SHARES, SAMPLE_FOLDERS) | ||
584 | 717 | result = yield self.be.volumes_info() | ||
585 | 718 | self.assertEqual(result, expected) | ||
586 | 719 | |||
587 | 720 | @inlineCallbacks | ||
588 | 642 | def test_subscribe_volume_folder(self): | 721 | def test_subscribe_volume_folder(self): |
589 | 643 | """The subscribe_volume method subscribes a folder.""" | 722 | """The subscribe_volume method subscribes a folder.""" |
590 | 644 | fid = '0123-4567' | 723 | fid = '0123-4567' |