Merge lp:~nataliabidart/ubuntuone-control-panel/computer-to-cloud-page into lp:ubuntuone-control-panel
- computer-to-cloud-page
- Merge into trunk
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Roberto Alsina | ||||||||
Approved revision: | 296 | ||||||||
Merged at revision: | 290 | ||||||||
Proposed branch: | lp:~nataliabidart/ubuntuone-control-panel/computer-to-cloud-page | ||||||||
Merge into: | lp:ubuntuone-control-panel | ||||||||
Prerequisite: | lp:~nataliabidart/ubuntuone-control-panel/cloud-to-computer-page | ||||||||
Diff against target: |
1319 lines (+848/-56) 16 files modified
data/qt/controlpanel.ui (+7/-2) data/qt/local_folders.ui (+179/-0) ubuntuone/controlpanel/gui/__init__.py (+10/-0) ubuntuone/controlpanel/gui/qt/addfolder.py (+9/-5) ubuntuone/controlpanel/gui/qt/controlpanel.py (+4/-2) ubuntuone/controlpanel/gui/qt/folders.py (+298/-1) ubuntuone/controlpanel/gui/qt/gotoweb.py (+17/-1) ubuntuone/controlpanel/gui/qt/tests/test_addfolder.py (+16/-7) ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py (+1/-1) ubuntuone/controlpanel/gui/qt/tests/test_folders.py (+206/-0) ubuntuone/controlpanel/gui/qt/tests/test_gotoweb.py (+24/-5) ubuntuone/controlpanel/gui/qt/tests/test_wizard.py (+33/-15) ubuntuone/controlpanel/gui/qt/wizard.py (+33/-7) ubuntuone/controlpanel/tests/__init__.py (+9/-0) ubuntuone/controlpanel/tests/test_login_client.py (+1/-5) ubuntuone/controlpanel/tests/test_sd_client.py (+1/-5) |
||||||||
To merge this branch: | bzr merge lp:~nataliabidart/ubuntuone-control-panel/computer-to-cloud-page | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Roberto Alsina (community) | Approve | ||
Eric Casteleijn (community) | Approve | ||
Review via email: mp+98286@code.launchpad.net |
Description of the change
To test IRL, please have nightlies installed and up to date. Then, from this branch, please run:
./setup.py clean build; U1_DEBUG=True PYTHONPATH=. bin/ubuntuone-
Assuming you already have U1 credentials, go to the devices tab and remove the current device. You will be presented with the initial screen, where you can play with:
From the dependency branch, you will get:
- closing from the button in the right bottom corner, you should get a confirmation dialog
- after login/register you should be presented with a screen to choose cloud folders to sync from your cloud to your desktop
- optionally, you can play with settings clicking on the button at the end of the folder listing
From this branch, you will get an additional page at the end to choose local folders to sync to your cloud. The list will offer some 'suggested' folders, and you can also add a custom folder using the 'add folder' button. Please note that changes will get applied *only* when the finish button is clicked.
Known bugs from this branch:
- 296. By Natalia Bidart
-
Merged trunk in.
Roberto Alsina (ralsina) wrote : | # |
+1 excellent work!
Preview Diff
1 | === modified file 'data/qt/controlpanel.ui' | |||
2 | --- data/qt/controlpanel.ui 2012-03-12 20:29:41 +0000 | |||
3 | +++ data/qt/controlpanel.ui 2012-03-19 21:32:18 +0000 | |||
4 | @@ -153,9 +153,9 @@ | |||
5 | 153 | </widget> | 153 | </widget> |
6 | 154 | </item> | 154 | </item> |
7 | 155 | <item> | 155 | <item> |
9 | 156 | <widget class="GoToWebButton" name="get_more_space_button"> | 156 | <widget class="GetStorageButton" name="get_more_space_button"> |
10 | 157 | <property name="text"> | 157 | <property name="text"> |
12 | 158 | <string notr="true">Get more storage</string> | 158 | <string notr="true">foo bar baz</string> |
13 | 159 | </property> | 159 | </property> |
14 | 160 | <property name="default"> | 160 | <property name="default"> |
15 | 161 | <bool>true</bool> | 161 | <bool>true</bool> |
16 | @@ -362,6 +362,11 @@ | |||
17 | 362 | </widget> | 362 | </widget> |
18 | 363 | <customwidgets> | 363 | <customwidgets> |
19 | 364 | <customwidget> | 364 | <customwidget> |
20 | 365 | <class>GetStorageButton</class> | ||
21 | 366 | <extends>QPushButton</extends> | ||
22 | 367 | <header>ubuntuone.controlpanel.gui.qt.gotoweb</header> | ||
23 | 368 | </customwidget> | ||
24 | 369 | <customwidget> | ||
25 | 365 | <class>GoToWebButton</class> | 370 | <class>GoToWebButton</class> |
26 | 366 | <extends>QPushButton</extends> | 371 | <extends>QPushButton</extends> |
27 | 367 | <header>ubuntuone.controlpanel.gui.qt.gotoweb</header> | 372 | <header>ubuntuone.controlpanel.gui.qt.gotoweb</header> |
28 | 368 | 373 | ||
29 | === added file 'data/qt/local_folders.ui' | |||
30 | --- data/qt/local_folders.ui 1970-01-01 00:00:00 +0000 | |||
31 | +++ data/qt/local_folders.ui 2012-03-19 21:32:18 +0000 | |||
32 | @@ -0,0 +1,179 @@ | |||
33 | 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
34 | 2 | <ui version="4.0"> | ||
35 | 3 | <class>Form</class> | ||
36 | 4 | <widget class="QWidget" name="Form"> | ||
37 | 5 | <property name="geometry"> | ||
38 | 6 | <rect> | ||
39 | 7 | <x>0</x> | ||
40 | 8 | <y>0</y> | ||
41 | 9 | <width>274</width> | ||
42 | 10 | <height>312</height> | ||
43 | 11 | </rect> | ||
44 | 12 | </property> | ||
45 | 13 | <layout class="QVBoxLayout" name="verticalLayout_2"> | ||
46 | 14 | <property name="topMargin"> | ||
47 | 15 | <number>0</number> | ||
48 | 16 | </property> | ||
49 | 17 | <item> | ||
50 | 18 | <widget class="QTreeWidget" name="folders"> | ||
51 | 19 | <property name="verticalScrollBarPolicy"> | ||
52 | 20 | <enum>Qt::ScrollBarAlwaysOn</enum> | ||
53 | 21 | </property> | ||
54 | 22 | <property name="alternatingRowColors"> | ||
55 | 23 | <bool>true</bool> | ||
56 | 24 | </property> | ||
57 | 25 | <property name="indentation"> | ||
58 | 26 | <number>0</number> | ||
59 | 27 | </property> | ||
60 | 28 | <property name="rootIsDecorated"> | ||
61 | 29 | <bool>false</bool> | ||
62 | 30 | </property> | ||
63 | 31 | <property name="uniformRowHeights"> | ||
64 | 32 | <bool>true</bool> | ||
65 | 33 | </property> | ||
66 | 34 | <property name="allColumnsShowFocus"> | ||
67 | 35 | <bool>true</bool> | ||
68 | 36 | </property> | ||
69 | 37 | <attribute name="headerStretchLastSection"> | ||
70 | 38 | <bool>false</bool> | ||
71 | 39 | </attribute> | ||
72 | 40 | <column> | ||
73 | 41 | <property name="text"> | ||
74 | 42 | <string notr="true">Sync these folders on my computer</string> | ||
75 | 43 | </property> | ||
76 | 44 | </column> | ||
77 | 45 | <column> | ||
78 | 46 | <property name="text"> | ||
79 | 47 | <string notr="true">Space (Total)</string> | ||
80 | 48 | </property> | ||
81 | 49 | </column> | ||
82 | 50 | </widget> | ||
83 | 51 | </item> | ||
84 | 52 | <item> | ||
85 | 53 | <layout class="QHBoxLayout" name="horizontalLayout_3"> | ||
86 | 54 | <item> | ||
87 | 55 | <spacer name="horizontalSpacer_4"> | ||
88 | 56 | <property name="orientation"> | ||
89 | 57 | <enum>Qt::Horizontal</enum> | ||
90 | 58 | </property> | ||
91 | 59 | <property name="sizeHint" stdset="0"> | ||
92 | 60 | <size> | ||
93 | 61 | <width>40</width> | ||
94 | 62 | <height>20</height> | ||
95 | 63 | </size> | ||
96 | 64 | </property> | ||
97 | 65 | </spacer> | ||
98 | 66 | </item> | ||
99 | 67 | <item> | ||
100 | 68 | <widget class="AddFolderButton" name="add_folder_button"> | ||
101 | 69 | <property name="text"> | ||
102 | 70 | <string notr="true">Add a folder</string> | ||
103 | 71 | </property> | ||
104 | 72 | <property name="default"> | ||
105 | 73 | <bool>true</bool> | ||
106 | 74 | </property> | ||
107 | 75 | <property name="DisabledState" stdset="0"> | ||
108 | 76 | <bool>false</bool> | ||
109 | 77 | </property> | ||
110 | 78 | </widget> | ||
111 | 79 | </item> | ||
112 | 80 | <item> | ||
113 | 81 | <spacer name="horizontalSpacer_5"> | ||
114 | 82 | <property name="orientation"> | ||
115 | 83 | <enum>Qt::Horizontal</enum> | ||
116 | 84 | </property> | ||
117 | 85 | <property name="sizeHint" stdset="0"> | ||
118 | 86 | <size> | ||
119 | 87 | <width>40</width> | ||
120 | 88 | <height>20</height> | ||
121 | 89 | </size> | ||
122 | 90 | </property> | ||
123 | 91 | </spacer> | ||
124 | 92 | </item> | ||
125 | 93 | </layout> | ||
126 | 94 | </item> | ||
127 | 95 | <item> | ||
128 | 96 | <widget class="QFrame" name="offer_frame"> | ||
129 | 97 | <layout class="QVBoxLayout" name="verticalLayout"> | ||
130 | 98 | <property name="leftMargin"> | ||
131 | 99 | <number>0</number> | ||
132 | 100 | </property> | ||
133 | 101 | <property name="rightMargin"> | ||
134 | 102 | <number>0</number> | ||
135 | 103 | </property> | ||
136 | 104 | <item> | ||
137 | 105 | <widget class="QLabel" name="offer_label"> | ||
138 | 106 | <property name="text"> | ||
139 | 107 | <string notr="true">overflow message</string> | ||
140 | 108 | </property> | ||
141 | 109 | <property name="wordWrap"> | ||
142 | 110 | <bool>true</bool> | ||
143 | 111 | </property> | ||
144 | 112 | </widget> | ||
145 | 113 | </item> | ||
146 | 114 | <item> | ||
147 | 115 | <layout class="QHBoxLayout" name="horizontalLayout"> | ||
148 | 116 | <item> | ||
149 | 117 | <spacer name="horizontalSpacer"> | ||
150 | 118 | <property name="orientation"> | ||
151 | 119 | <enum>Qt::Horizontal</enum> | ||
152 | 120 | </property> | ||
153 | 121 | <property name="sizeHint" stdset="0"> | ||
154 | 122 | <size> | ||
155 | 123 | <width>40</width> | ||
156 | 124 | <height>20</height> | ||
157 | 125 | </size> | ||
158 | 126 | </property> | ||
159 | 127 | </spacer> | ||
160 | 128 | </item> | ||
161 | 129 | <item> | ||
162 | 130 | <widget class="GetStorageButton" name="add_storage_button"> | ||
163 | 131 | <property name="sizePolicy"> | ||
164 | 132 | <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> | ||
165 | 133 | <horstretch>0</horstretch> | ||
166 | 134 | <verstretch>0</verstretch> | ||
167 | 135 | </sizepolicy> | ||
168 | 136 | </property> | ||
169 | 137 | <property name="text"> | ||
170 | 138 | <string notr="true">add storage</string> | ||
171 | 139 | </property> | ||
172 | 140 | <property name="default"> | ||
173 | 141 | <bool>true</bool> | ||
174 | 142 | </property> | ||
175 | 143 | </widget> | ||
176 | 144 | </item> | ||
177 | 145 | <item> | ||
178 | 146 | <spacer name="horizontalSpacer_2"> | ||
179 | 147 | <property name="orientation"> | ||
180 | 148 | <enum>Qt::Horizontal</enum> | ||
181 | 149 | </property> | ||
182 | 150 | <property name="sizeHint" stdset="0"> | ||
183 | 151 | <size> | ||
184 | 152 | <width>40</width> | ||
185 | 153 | <height>20</height> | ||
186 | 154 | </size> | ||
187 | 155 | </property> | ||
188 | 156 | </spacer> | ||
189 | 157 | </item> | ||
190 | 158 | </layout> | ||
191 | 159 | </item> | ||
192 | 160 | </layout> | ||
193 | 161 | </widget> | ||
194 | 162 | </item> | ||
195 | 163 | </layout> | ||
196 | 164 | </widget> | ||
197 | 165 | <customwidgets> | ||
198 | 166 | <customwidget> | ||
199 | 167 | <class>GetStorageButton</class> | ||
200 | 168 | <extends>QPushButton</extends> | ||
201 | 169 | <header>ubuntuone.controlpanel.gui.qt.gotoweb</header> | ||
202 | 170 | </customwidget> | ||
203 | 171 | <customwidget> | ||
204 | 172 | <class>AddFolderButton</class> | ||
205 | 173 | <extends>QPushButton</extends> | ||
206 | 174 | <header>ubuntuone.controlpanel.gui.qt.addfolder</header> | ||
207 | 175 | </customwidget> | ||
208 | 176 | </customwidgets> | ||
209 | 177 | <resources/> | ||
210 | 178 | <connections/> | ||
211 | 179 | </ui> | ||
212 | 0 | 180 | ||
213 | === modified file 'ubuntuone/controlpanel/gui/__init__.py' | |||
214 | --- ubuntuone/controlpanel/gui/__init__.py 2012-03-16 21:18:43 +0000 | |||
215 | +++ ubuntuone/controlpanel/gui/__init__.py 2012-03-19 21:32:18 +0000 | |||
216 | @@ -71,6 +71,7 @@ | |||
217 | 71 | EDIT_PROFILE_LINK = u'https://login.ubuntu.com/' | 71 | EDIT_PROFILE_LINK = u'https://login.ubuntu.com/' |
218 | 72 | EDIT_SERVICES_LINK = UBUNTUONE_LINK + u'services' | 72 | EDIT_SERVICES_LINK = UBUNTUONE_LINK + u'services' |
219 | 73 | FACEBOOK_LINK = u'http://www.facebook.com/ubuntuone/' | 73 | FACEBOOK_LINK = u'http://www.facebook.com/ubuntuone/' |
220 | 74 | GET_STORAGE_LINK = UBUNTUONE_LINK + u'services/#storage_panel' | ||
221 | 74 | GET_SUPPORT_LINK = UBUNTUONE_LINK + u'support/' | 75 | GET_SUPPORT_LINK = UBUNTUONE_LINK + u'support/' |
222 | 75 | LEARN_MORE_LINK = UBUNTUONE_LINK | 76 | LEARN_MORE_LINK = UBUNTUONE_LINK |
223 | 76 | MANAGE_FILES_LINK = UBUNTUONE_LINK + u'files/' | 77 | MANAGE_FILES_LINK = UBUNTUONE_LINK + u'files/' |
224 | @@ -93,6 +94,9 @@ | |||
225 | 93 | CLOUD_TO_COMPUTER_SUBTITLE = _('These are the folders in your cloud. ' | 94 | CLOUD_TO_COMPUTER_SUBTITLE = _('These are the folders in your cloud. ' |
226 | 94 | 'Select the ones you want to sync with this computer.') | 95 | 'Select the ones you want to sync with this computer.') |
227 | 95 | CLOUD_TO_COMPUTER_TITLE = _('Syncing the cloud to your computer') | 96 | CLOUD_TO_COMPUTER_TITLE = _('Syncing the cloud to your computer') |
228 | 97 | COMPUTER_TO_CLOUD_SUBTITLE = _('Okay! Now it\'s time to choose which folders ' | ||
229 | 98 | 'on this computer you would like to sync to the cloud.') | ||
230 | 99 | COMPUTER_TO_CLOUD_TITLE = _('Syncing your computer with the cloud') | ||
231 | 96 | CONNECT_BUTTON_LABEL = _('Connect to Ubuntu One') | 100 | CONNECT_BUTTON_LABEL = _('Connect to Ubuntu One') |
232 | 97 | CONTACTS = _('Thunderbird plug-in') | 101 | CONTACTS = _('Thunderbird plug-in') |
233 | 98 | CREDENTIALS_ERROR = _('There was a problem while retrieving the credentials.') | 102 | CREDENTIALS_ERROR = _('There was a problem while retrieving the credentials.') |
234 | @@ -177,6 +181,12 @@ | |||
235 | 177 | INSTALLING = _('Installation of <i>%(package_name)s</i> in progress') | 181 | INSTALLING = _('Installation of <i>%(package_name)s</i> in progress') |
236 | 178 | LOADING = _('Loading...') | 182 | LOADING = _('Loading...') |
237 | 179 | LOADING_OVERLAY = _('Getting information, please wait...') | 183 | LOADING_OVERLAY = _('Getting information, please wait...') |
238 | 184 | LOCAL_FOLDERS_CALCULATING = _('Calculating...') | ||
239 | 185 | LOCAL_FOLDERS_OVERFLOW = _('The folders you have selected to sync take ' | ||
240 | 186 | 'over your {quota_total} space. ' | ||
241 | 187 | 'You can remove some folders or add some extra storage.') | ||
242 | 188 | LOCAL_FOLDERS_FOLDER_HEADER = _('Sync these folders on my computer') | ||
243 | 189 | LOCAL_FOLDERS_SPACE_HEADER = _('Space {space_total}') | ||
244 | 180 | MAIN_ACCOUNT_TAB = _('Account information') | 190 | MAIN_ACCOUNT_TAB = _('Account information') |
245 | 181 | MAIN_DEVICES_TAB = _('Devices') | 191 | MAIN_DEVICES_TAB = _('Devices') |
246 | 182 | MAIN_FOLDERS_TAB = _('Folders') | 192 | MAIN_FOLDERS_TAB = _('Folders') |
247 | 183 | 193 | ||
248 | === modified file 'ubuntuone/controlpanel/gui/qt/addfolder.py' | |||
249 | --- ubuntuone/controlpanel/gui/qt/addfolder.py 2012-03-09 14:16:38 +0000 | |||
250 | +++ ubuntuone/controlpanel/gui/qt/addfolder.py 2012-03-19 21:32:18 +0000 | |||
251 | @@ -56,6 +56,8 @@ | |||
252 | 56 | def __init__(self, *args, **kwargs): | 56 | def __init__(self, *args, **kwargs): |
253 | 57 | """Initialize the UI of the widget.""" | 57 | """Initialize the UI of the widget.""" |
254 | 58 | super(AddFolderButton, self).__init__(*args, **kwargs) | 58 | super(AddFolderButton, self).__init__(*args, **kwargs) |
255 | 59 | self.add_folder_func = \ | ||
256 | 60 | lambda *a, **kw: defer.fail(NotImplementedError()) | ||
257 | 59 | self.cloud_folders = [] | 61 | self.cloud_folders = [] |
258 | 60 | self.clicked.connect(self.on_clicked) | 62 | self.clicked.connect(self.on_clicked) |
259 | 61 | 63 | ||
260 | @@ -70,18 +72,20 @@ | |||
261 | 70 | parent=self, directory=home_dir, | 72 | parent=self, directory=home_dir, |
262 | 71 | options=FILE_CHOOSER_OPTIONS) | 73 | options=FILE_CHOOSER_OPTIONS) |
263 | 72 | folder = unicode(QtCore.QDir.toNativeSeparators(folder)) | 74 | folder = unicode(QtCore.QDir.toNativeSeparators(folder)) |
266 | 73 | logger.debug('on_add_folder_button_clicked: user requested folder ' | 75 | logger.info('on_add_folder_button_clicked: user requested folder ' |
267 | 74 | 'creation for path %r', folder) | 76 | 'creation for path %r.', folder) |
268 | 75 | if folder == '': | 77 | if folder == '': |
269 | 76 | self.folderCreationCanceled.emit() | 78 | self.folderCreationCanceled.emit() |
271 | 77 | return | 79 | defer.returnValue(None) |
272 | 78 | 80 | ||
273 | 79 | is_valid = yield self.backend.validate_path_for_folder(folder) | 81 | is_valid = yield self.backend.validate_path_for_folder(folder) |
274 | 80 | if not is_valid: | 82 | if not is_valid: |
275 | 83 | logger.error('on_add_folder_button_clicked: user requested to ' | ||
276 | 84 | 'create a folder for an invalid path %r.', folder) | ||
277 | 81 | text = FOLDER_INVALID_PATH % {'folder_path': folder, | 85 | text = FOLDER_INVALID_PATH % {'folder_path': folder, |
278 | 82 | 'home_folder': home_dir} | 86 | 'home_folder': home_dir} |
279 | 83 | QtGui.QMessageBox.warning(self, '', text, CLOSE) | 87 | QtGui.QMessageBox.warning(self, '', text, CLOSE) |
281 | 84 | return | 88 | defer.returnValue(None) |
282 | 85 | 89 | ||
284 | 86 | yield self.backend.create_folder(folder_path=folder) | 90 | yield self.add_folder_func(folder_path=folder) |
285 | 87 | self.folderCreated.emit(folder) | 91 | self.folderCreated.emit(folder) |
286 | 88 | 92 | ||
287 | === modified file 'ubuntuone/controlpanel/gui/qt/controlpanel.py' | |||
288 | --- ubuntuone/controlpanel/gui/qt/controlpanel.py 2012-03-16 21:12:20 +0000 | |||
289 | +++ ubuntuone/controlpanel/gui/qt/controlpanel.py 2012-03-19 21:32:18 +0000 | |||
290 | @@ -24,10 +24,10 @@ | |||
291 | 24 | from ubuntuone.controlpanel.backend import AUTOCONNECT_KEY | 24 | from ubuntuone.controlpanel.backend import AUTOCONNECT_KEY |
292 | 25 | from ubuntuone.controlpanel.logger import setup_logging, log_call | 25 | from ubuntuone.controlpanel.logger import setup_logging, log_call |
293 | 26 | from ubuntuone.controlpanel.gui import ( | 26 | from ubuntuone.controlpanel.gui import ( |
294 | 27 | EDIT_SERVICES_LINK, | ||
295 | 28 | FACEBOOK_LINK, | 27 | FACEBOOK_LINK, |
296 | 29 | GET_HELP_ONLINE, | 28 | GET_HELP_ONLINE, |
297 | 30 | GET_MORE_STORAGE, | 29 | GET_MORE_STORAGE, |
298 | 30 | GET_STORAGE_LINK, | ||
299 | 31 | GET_SUPPORT_LINK, | 31 | GET_SUPPORT_LINK, |
300 | 32 | GREETING, | 32 | GREETING, |
301 | 33 | humanize, | 33 | humanize, |
302 | @@ -63,7 +63,7 @@ | |||
303 | 63 | def _setup(self): | 63 | def _setup(self): |
304 | 64 | """Do some extra setupping for the UI.""" | 64 | """Do some extra setupping for the UI.""" |
305 | 65 | self.ui.get_more_space_button.setText(GET_MORE_STORAGE) | 65 | self.ui.get_more_space_button.setText(GET_MORE_STORAGE) |
307 | 66 | self.ui.get_more_space_button.uri = EDIT_SERVICES_LINK | 66 | self.ui.get_more_space_button.uri = GET_STORAGE_LINK |
308 | 67 | 67 | ||
309 | 68 | self.ui.help_button.setText(GET_HELP_ONLINE) | 68 | self.ui.help_button.setText(GET_HELP_ONLINE) |
310 | 69 | self.ui.help_button.uri = GET_SUPPORT_LINK | 69 | self.ui.help_button.uri = GET_SUPPORT_LINK |
311 | @@ -100,6 +100,8 @@ | |||
312 | 100 | @log_call(logger.debug) | 100 | @log_call(logger.debug) |
313 | 101 | def on_credentials_found(self): | 101 | def on_credentials_found(self): |
314 | 102 | """Credentials are not found or were removed.""" | 102 | """Credentials are not found or were removed.""" |
315 | 103 | folders_tab_idx = self.ui.tab_widget.indexOf(self.ui.folders_tab) | ||
316 | 104 | self.ui.tab_widget.setCurrentIndex(folders_tab_idx) | ||
317 | 103 | self.ui.switcher.setCurrentWidget(self.ui.management) | 105 | self.ui.switcher.setCurrentWidget(self.ui.management) |
318 | 104 | self.connect_file_sync() | 106 | self.connect_file_sync() |
319 | 105 | self.is_processing = False | 107 | self.is_processing = False |
320 | 106 | 108 | ||
321 | === modified file 'ubuntuone/controlpanel/gui/qt/folders.py' | |||
322 | --- ubuntuone/controlpanel/gui/qt/folders.py 2012-03-19 13:47:56 +0000 | |||
323 | +++ ubuntuone/controlpanel/gui/qt/folders.py 2012-03-19 21:32:18 +0000 | |||
324 | @@ -19,10 +19,13 @@ | |||
325 | 19 | from __future__ import division | 19 | from __future__ import division |
326 | 20 | 20 | ||
327 | 21 | import os | 21 | import os |
328 | 22 | import Queue | ||
329 | 23 | import threading | ||
330 | 22 | 24 | ||
331 | 23 | from PyQt4 import QtGui, QtCore | 25 | from PyQt4 import QtGui, QtCore |
332 | 24 | from twisted.internet import defer | 26 | from twisted.internet import defer |
333 | 25 | 27 | ||
334 | 28 | from ubuntuone.controlpanel.utils import default_folders | ||
335 | 26 | from ubuntuone.controlpanel.logger import setup_logging, log_call | 29 | from ubuntuone.controlpanel.logger import setup_logging, log_call |
336 | 27 | from ubuntuone.controlpanel.gui import ( | 30 | from ubuntuone.controlpanel.gui import ( |
337 | 28 | ALWAYS_SUBSCRIBED, | 31 | ALWAYS_SUBSCRIBED, |
338 | @@ -35,6 +38,12 @@ | |||
339 | 35 | FOLDERS_COLUMN_SYNC_LOCALLY, | 38 | FOLDERS_COLUMN_SYNC_LOCALLY, |
340 | 36 | FOLDERS_CONFIRM_MERGE, | 39 | FOLDERS_CONFIRM_MERGE, |
341 | 37 | FOLDERS_MANAGE_LABEL, | 40 | FOLDERS_MANAGE_LABEL, |
342 | 41 | GET_MORE_STORAGE, | ||
343 | 42 | humanize, | ||
344 | 43 | LOCAL_FOLDERS_CALCULATING, | ||
345 | 44 | LOCAL_FOLDERS_FOLDER_HEADER, | ||
346 | 45 | LOCAL_FOLDERS_OVERFLOW, | ||
347 | 46 | LOCAL_FOLDERS_SPACE_HEADER, | ||
348 | 38 | MANAGE_FILES_LINK, | 47 | MANAGE_FILES_LINK, |
349 | 39 | MUSIC_ICON_NAME, | 48 | MUSIC_ICON_NAME, |
350 | 40 | MUSIC_DISPLAY_NAME, | 49 | MUSIC_DISPLAY_NAME, |
351 | @@ -48,7 +57,7 @@ | |||
352 | 48 | uri_hook, | 57 | uri_hook, |
353 | 49 | ) | 58 | ) |
354 | 50 | from ubuntuone.controlpanel.gui.qt.ubuntuonebin import UbuntuOneBin | 59 | from ubuntuone.controlpanel.gui.qt.ubuntuonebin import UbuntuOneBin |
356 | 51 | from ubuntuone.controlpanel.gui.qt.ui import folders_ui | 60 | from ubuntuone.controlpanel.gui.qt.ui import folders_ui, local_folders_ui |
357 | 52 | 61 | ||
358 | 53 | 62 | ||
359 | 54 | logger = setup_logging('qt.folders') | 63 | logger = setup_logging('qt.folders') |
360 | @@ -57,6 +66,9 @@ | |||
361 | 57 | SUBSCRIPTION_COL = 1 | 66 | SUBSCRIPTION_COL = 1 |
362 | 58 | EXPLORE_COL = 2 | 67 | EXPLORE_COL = 2 |
363 | 59 | 68 | ||
364 | 69 | LOCAL_SUBSCRIPTION_COL = 0 | ||
365 | 70 | LOCAL_SPACE_COL = 1 | ||
366 | 71 | |||
367 | 60 | CANCEL = QtGui.QMessageBox.Cancel | 72 | CANCEL = QtGui.QMessageBox.Cancel |
368 | 61 | CHECKED = QtCore.Qt.Checked | 73 | CHECKED = QtCore.Qt.Checked |
369 | 62 | CLOSE = QtGui.QMessageBox.Close | 74 | CLOSE = QtGui.QMessageBox.Close |
370 | @@ -102,6 +114,7 @@ | |||
371 | 102 | super(FoldersPanel, self)._setup() | 114 | super(FoldersPanel, self)._setup() |
372 | 103 | self.ui.add_folder_button.folderCreated.connect(self.on_folder_created) | 115 | self.ui.add_folder_button.folderCreated.connect(self.on_folder_created) |
373 | 104 | self.ui.add_folder_button.setText(FOLDERS_BUTTON_ADD_FOLDER) | 116 | self.ui.add_folder_button.setText(FOLDERS_BUTTON_ADD_FOLDER) |
374 | 117 | self.ui.add_folder_button.add_folder_func = self.backend.create_folder | ||
375 | 105 | 118 | ||
376 | 106 | self.ui.share_publish_button.setVisible(not self.remote_folders) | 119 | self.ui.share_publish_button.setVisible(not self.remote_folders) |
377 | 107 | self.ui.add_folder_button.setVisible(not self.remote_folders) | 120 | self.ui.add_folder_button.setVisible(not self.remote_folders) |
378 | @@ -328,3 +341,287 @@ | |||
379 | 328 | """The Folders Panel that only shows remote cloud folders.""" | 341 | """The Folders Panel that only shows remote cloud folders.""" |
380 | 329 | 342 | ||
381 | 330 | remote_folders = True | 343 | remote_folders = True |
382 | 344 | |||
383 | 345 | |||
384 | 346 | class CalculateSize(threading.Thread): | ||
385 | 347 | """A thread that calculates, in the background, the size of a folder.""" | ||
386 | 348 | |||
387 | 349 | def __init__(self, path_name, queue): | ||
388 | 350 | self.path_name = path_name | ||
389 | 351 | self.queue = queue | ||
390 | 352 | self._stop = False | ||
391 | 353 | |||
392 | 354 | super(CalculateSize, self).__init__() | ||
393 | 355 | |||
394 | 356 | # http://docs.python.org/library/threading.html#threading.Thread.daemon | ||
395 | 357 | # "A boolean value indicating whether this thread is a daemon thread | ||
396 | 358 | # (True) or not (False)" | ||
397 | 359 | self.daemon = True | ||
398 | 360 | |||
399 | 361 | def run(self): | ||
400 | 362 | """Run this thread.""" | ||
401 | 363 | logger.debug('size_calculator: about to calculate size for %r.', | ||
402 | 364 | self.path_name) | ||
403 | 365 | try: | ||
404 | 366 | total_size = 0 | ||
405 | 367 | for dirpath, _, filenames in os.walk(self.path_name): | ||
406 | 368 | for f in filenames: | ||
407 | 369 | fp = os.path.join(dirpath, f) | ||
408 | 370 | if os.path.isfile(fp): | ||
409 | 371 | total_size += os.path.getsize(fp) | ||
410 | 372 | if self._stop: | ||
411 | 373 | logger.warning('size_calculator: stopping due to external ' | ||
412 | 374 | 'request.') | ||
413 | 375 | return | ||
414 | 376 | except: # pylint: disable=W0702 | ||
415 | 377 | logger.exception('size_calculator: failed for %r:', self.path_name) | ||
416 | 378 | else: | ||
417 | 379 | logger.info('size_calculator: added new size %r for %r.', | ||
418 | 380 | self.path_name, total_size) | ||
419 | 381 | self.queue.put([self.path_name, total_size]) | ||
420 | 382 | |||
421 | 383 | |||
422 | 384 | class FolderItem(QtGui.QTreeWidgetItem): | ||
423 | 385 | """A folder in the local folder list.""" | ||
424 | 386 | |||
425 | 387 | def __init__(self, values=None, path=None, queue=None, volume_id=None): | ||
426 | 388 | super(FolderItem, self).__init__(values) | ||
427 | 389 | self.path = path | ||
428 | 390 | self.volume_id = volume_id | ||
429 | 391 | self.thread = None | ||
430 | 392 | self.size = 0 | ||
431 | 393 | |||
432 | 394 | state = UNCHECKED | ||
433 | 395 | if path is not None: | ||
434 | 396 | if volume_id is not None: | ||
435 | 397 | state = CHECKED | ||
436 | 398 | elif queue is not None: | ||
437 | 399 | # calculate sizes of non-existing folders | ||
438 | 400 | self.thread = CalculateSize(path, queue) | ||
439 | 401 | self.thread.start() | ||
440 | 402 | self.size = None | ||
441 | 403 | |||
442 | 404 | self.setCheckState(LOCAL_SUBSCRIPTION_COL, state) | ||
443 | 405 | |||
444 | 406 | |||
445 | 407 | class LocalFoldersPanel(UbuntuOneBin): | ||
446 | 408 | """The panel that only shows local, non-synched folders.""" | ||
447 | 409 | |||
448 | 410 | changesApplied = QtCore.pyqtSignal() | ||
449 | 411 | changesCanceled = QtCore.pyqtSignal() | ||
450 | 412 | logger = logger | ||
451 | 413 | ui_class = local_folders_ui | ||
452 | 414 | |||
453 | 415 | def __init__(self, *args, **kwargs): | ||
454 | 416 | super(LocalFoldersPanel, self).__init__(*args, **kwargs) | ||
455 | 417 | self.queue = Queue.Queue() | ||
456 | 418 | self.timer = QtCore.QTimer() | ||
457 | 419 | self.items = {} | ||
458 | 420 | self.user_home = None | ||
459 | 421 | self.account_info = None | ||
460 | 422 | |||
461 | 423 | def _setup(self): | ||
462 | 424 | """Do some extra setupping for the UI.""" | ||
463 | 425 | super(LocalFoldersPanel, self)._setup() | ||
464 | 426 | # Start with storage upgrade offer invisible | ||
465 | 427 | self.ui.offer_frame.setVisible(False) | ||
466 | 428 | |||
467 | 429 | headers = self.ui.folders.header() | ||
468 | 430 | headers.setResizeMode(LOCAL_SUBSCRIPTION_COL, headers.Stretch) | ||
469 | 431 | headers.setResizeMode(LOCAL_SPACE_COL, headers.Custom) | ||
470 | 432 | headers.resizeSection(LOCAL_SPACE_COL, 130) | ||
471 | 433 | |||
472 | 434 | self.ui.folders.headerItem().setText(LOCAL_SUBSCRIPTION_COL, | ||
473 | 435 | LOCAL_FOLDERS_FOLDER_HEADER) | ||
474 | 436 | self._set_space_header() | ||
475 | 437 | |||
476 | 438 | self.ui.add_folder_button.folderCreated.connect(self.on_folder_created) | ||
477 | 439 | self.ui.add_folder_button.setText(FOLDERS_BUTTON_ADD_FOLDER) | ||
478 | 440 | self.ui.add_folder_button.add_folder_func = self.add_folder | ||
479 | 441 | |||
480 | 442 | self.ui.add_storage_button.setText(GET_MORE_STORAGE) | ||
481 | 443 | |||
482 | 444 | def _set_space_header(self, total=None): | ||
483 | 445 | """Set the folders listing 'space' header.""" | ||
484 | 446 | if total is None: | ||
485 | 447 | total = '' | ||
486 | 448 | else: | ||
487 | 449 | try: | ||
488 | 450 | total = humanize(long(total)) | ||
489 | 451 | except (TypeError, ValueError): | ||
490 | 452 | pass | ||
491 | 453 | total = '(%s)' % total | ||
492 | 454 | |||
493 | 455 | title = LOCAL_FOLDERS_SPACE_HEADER.format(space_total=total) | ||
494 | 456 | self.ui.folders.headerItem().setText(LOCAL_SPACE_COL, title) | ||
495 | 457 | |||
496 | 458 | def _stop(self): | ||
497 | 459 | """Stop all pending threads and timers.""" | ||
498 | 460 | self.timer.stop() | ||
499 | 461 | self.timer = None | ||
500 | 462 | |||
501 | 463 | for item in self.items.itervalues(): | ||
502 | 464 | if item.thread is None: | ||
503 | 465 | logger.warning('LocalFoldersPanel: attempted to stop a thread ' | ||
504 | 466 | 'for an item with a None thread.') | ||
505 | 467 | else: | ||
506 | 468 | item.thread._stop = True | ||
507 | 469 | |||
508 | 470 | # pylint: disable=E0202 | ||
509 | 471 | @defer.inlineCallbacks | ||
510 | 472 | def load(self): | ||
511 | 473 | """Load specific tab info.""" | ||
512 | 474 | self.is_processing = True | ||
513 | 475 | self.account_info = yield self.backend.account_info() | ||
514 | 476 | self._set_space_header(self.account_info['quota_used']) | ||
515 | 477 | volumes_info = yield self.backend.volumes_info(with_storage_info=False) | ||
516 | 478 | yield self.process_info(volumes_info) | ||
517 | 479 | |||
518 | 480 | @defer.inlineCallbacks | ||
519 | 481 | @log_call(logger.debug) | ||
520 | 482 | def process_info(self, volumes_info): | ||
521 | 483 | """Load local folders info into the tree view.""" | ||
522 | 484 | try: | ||
523 | 485 | folders = [] | ||
524 | 486 | for _, _, volumes in volumes_info: | ||
525 | 487 | for volume in volumes: | ||
526 | 488 | if (volume[u'type'] == self.backend.FOLDER_TYPE and | ||
527 | 489 | bool(volume['subscribed'])): | ||
528 | 490 | folders.append((volume['path'], volume['volume_id'])) | ||
529 | 491 | |||
530 | 492 | # add local folders only if they are valid | ||
531 | 493 | self.user_home = yield self.backend.get_home_dir() | ||
532 | 494 | for folder in default_folders(user_home=self.user_home): | ||
533 | 495 | is_valid = yield self.backend.validate_path_for_folder(folder) | ||
534 | 496 | if is_valid: | ||
535 | 497 | folders.append((folder, None)) | ||
536 | 498 | |||
537 | 499 | # always clear the items dict first, since clearing the folders | ||
538 | 500 | # list will trigger "underlying C/C++ object has been deleted" | ||
539 | 501 | self.items.clear() | ||
540 | 502 | self.ui.folders.clear() | ||
541 | 503 | |||
542 | 504 | # self.timer can be None if self._stop was called before | ||
543 | 505 | # this piece of code was executed | ||
544 | 506 | if self.timer is not None: | ||
545 | 507 | for path, volume_id in folders: | ||
546 | 508 | self.add_folder(folder_path=path, volume_id=volume_id) | ||
547 | 509 | |||
548 | 510 | self.timer.start(2000) | ||
549 | 511 | self.timer.timeout.connect(self.update_sizes) | ||
550 | 512 | finally: | ||
551 | 513 | self.is_processing = False | ||
552 | 514 | |||
553 | 515 | @handle_errors(logger=logger) | ||
554 | 516 | @defer.inlineCallbacks | ||
555 | 517 | def apply_changes(self): | ||
556 | 518 | """When moving to next page, create/[un]subscribe UDFs.""" | ||
557 | 519 | self.is_processing = True | ||
558 | 520 | try: | ||
559 | 521 | self._stop() | ||
560 | 522 | |||
561 | 523 | for path, item in self.items.iteritems(): | ||
562 | 524 | subscribed = item.checkState(LOCAL_SUBSCRIPTION_COL) == CHECKED | ||
563 | 525 | if item.volume_id is not None: | ||
564 | 526 | logger.info('apply_changes: change settings for %r to %r.', | ||
565 | 527 | item.path, dict(subscribed=subscribed)) | ||
566 | 528 | yield self.backend.change_volume_settings(item.volume_id, | ||
567 | 529 | dict(subscribed=subscribed)) | ||
568 | 530 | else: | ||
569 | 531 | if subscribed: | ||
570 | 532 | logger.info('apply_changes: create folder for %r.', | ||
571 | 533 | path) | ||
572 | 534 | yield self.backend.create_folder(path) | ||
573 | 535 | finally: | ||
574 | 536 | self.is_processing = False | ||
575 | 537 | |||
576 | 538 | self.changesApplied.emit() | ||
577 | 539 | |||
578 | 540 | @handle_errors(logger=logger) | ||
579 | 541 | def add_folder(self, folder_path, volume_id=None): | ||
580 | 542 | """Add a folder to the list.""" | ||
581 | 543 | if folder_path in self.items: | ||
582 | 544 | logger.warning('LocalFoldersPanel: already have an item for %r.', | ||
583 | 545 | folder_path) | ||
584 | 546 | |||
585 | 547 | if self.user_home is None: | ||
586 | 548 | logger.warning('LocalFoldersPanel: user home is None! ' | ||
587 | 549 | 'paths will not be pretty.') | ||
588 | 550 | display_name = folder_path | ||
589 | 551 | else: | ||
590 | 552 | user_home = self.user_home + os.path.sep | ||
591 | 553 | display_name = _process_name(folder_path.replace(user_home, '')) | ||
592 | 554 | |||
593 | 555 | item = FolderItem([display_name, ""], path=folder_path, | ||
594 | 556 | queue=self.queue, volume_id=volume_id) | ||
595 | 557 | self.ui.folders.addTopLevelItem(item) | ||
596 | 558 | |||
597 | 559 | if volume_id is None: # new folder | ||
598 | 560 | self.items[folder_path] = item | ||
599 | 561 | |||
600 | 562 | @log_call(logger.info) | ||
601 | 563 | def on_folder_created(self, new_folder): | ||
602 | 564 | """User clicked on the "Add Folder" button.""" | ||
603 | 565 | item = self.items.get(unicode(new_folder)) | ||
604 | 566 | if item is not None: | ||
605 | 567 | item.setCheckState(LOCAL_SUBSCRIPTION_COL, CHECKED) | ||
606 | 568 | else: | ||
607 | 569 | logger.warning('LocalFoldersPanel: on_folder_created was called ' | ||
608 | 570 | 'for %r which is not tracked in the internal dict', | ||
609 | 571 | unicode(new_folder)) | ||
610 | 572 | |||
611 | 573 | @handle_errors(logger=logger) | ||
612 | 574 | def update_sizes(self): | ||
613 | 575 | """Poll the queue were the threads put the size info. | ||
614 | 576 | |||
615 | 577 | Every item put in this queue will be a non-synched folder. Thus, the | ||
616 | 578 | item's volume_id will be None, so no need to check that. | ||
617 | 579 | |||
618 | 580 | """ | ||
619 | 581 | while True: | ||
620 | 582 | try: | ||
621 | 583 | path, size = self.queue.get(block=False) | ||
622 | 584 | except Queue.Empty: | ||
623 | 585 | break | ||
624 | 586 | else: | ||
625 | 587 | item = self.items.get(path) | ||
626 | 588 | if item: | ||
627 | 589 | item.size = size | ||
628 | 590 | item.setText(LOCAL_SPACE_COL, humanize(size)) | ||
629 | 591 | |||
630 | 592 | total = long(self.account_info['quota_used']) | ||
631 | 593 | for path, item in self.items.iteritems(): | ||
632 | 594 | if item.size is None: | ||
633 | 595 | total = LOCAL_FOLDERS_CALCULATING | ||
634 | 596 | break | ||
635 | 597 | |||
636 | 598 | subscribed = item.checkState(LOCAL_SUBSCRIPTION_COL) == CHECKED | ||
637 | 599 | if subscribed: | ||
638 | 600 | total += item.size | ||
639 | 601 | |||
640 | 602 | if isinstance(total, long): | ||
641 | 603 | self.show_hide_offer(total) | ||
642 | 604 | else: | ||
643 | 605 | self.show_hide_offer(0) | ||
644 | 606 | |||
645 | 607 | self._set_space_header(total) | ||
646 | 608 | |||
647 | 609 | def show_hide_offer(self, current_size): | ||
648 | 610 | """Show or hide the offer to buy space according to the total size.""" | ||
649 | 611 | quota = long(self.account_info['quota_total']) | ||
650 | 612 | if current_size > quota: | ||
651 | 613 | msg = LOCAL_FOLDERS_OVERFLOW.format(quota_total=humanize(quota)) | ||
652 | 614 | self.ui.offer_label.setText(msg) | ||
653 | 615 | self.ui.offer_frame.setVisible(True) | ||
654 | 616 | else: | ||
655 | 617 | self.ui.offer_frame.setVisible(False) | ||
656 | 618 | |||
657 | 619 | # pylint: disable=C0103 | ||
658 | 620 | |||
659 | 621 | def on_folders_itemChanged(self, item, column): | ||
660 | 622 | """Update the size for the chosen row.""" | ||
661 | 623 | if column == LOCAL_SUBSCRIPTION_COL: | ||
662 | 624 | self.update_sizes() | ||
663 | 625 | self.items[item.path] = item | ||
664 | 626 | |||
665 | 627 | # pylint: enable=C0103 | ||
666 | 331 | 628 | ||
667 | === modified file 'ubuntuone/controlpanel/gui/qt/gotoweb.py' | |||
668 | --- ubuntuone/controlpanel/gui/qt/gotoweb.py 2012-02-06 15:23:27 +0000 | |||
669 | +++ ubuntuone/controlpanel/gui/qt/gotoweb.py 2012-03-19 21:32:18 +0000 | |||
670 | @@ -23,16 +23,25 @@ | |||
671 | 23 | from twisted.internet import defer | 23 | from twisted.internet import defer |
672 | 24 | 24 | ||
673 | 25 | from ubuntuone.controlpanel import cache | 25 | from ubuntuone.controlpanel import cache |
674 | 26 | from ubuntuone.controlpanel.gui import ( | ||
675 | 27 | GET_MORE_STORAGE, | ||
676 | 28 | GET_STORAGE_LINK, | ||
677 | 29 | ) | ||
678 | 26 | from ubuntuone.controlpanel.gui import qt | 30 | from ubuntuone.controlpanel.gui import qt |
679 | 27 | 31 | ||
680 | 28 | 32 | ||
681 | 29 | class GoToWebButton(cache.Cache, QtGui.QPushButton): | 33 | class GoToWebButton(cache.Cache, QtGui.QPushButton): |
682 | 30 | """The GoToWebButton widget""" | 34 | """The GoToWebButton widget""" |
683 | 31 | 35 | ||
684 | 36 | uri = None | ||
685 | 37 | legend = None | ||
686 | 38 | |||
687 | 32 | def __init__(self, *args, **kwargs): | 39 | def __init__(self, *args, **kwargs): |
688 | 33 | """Initialize the UI of the widget.""" | 40 | """Initialize the UI of the widget.""" |
689 | 34 | super(GoToWebButton, self).__init__(*args, **kwargs) | 41 | super(GoToWebButton, self).__init__(*args, **kwargs) |
691 | 35 | self.uri = None | 42 | if self.legend is not None: |
692 | 43 | self.setText(self.legend) | ||
693 | 44 | |||
694 | 36 | self.setIcon(qt.icon_from_name('external_icon_white')) | 45 | self.setIcon(qt.icon_from_name('external_icon_white')) |
695 | 37 | self.setLayoutDirection(QtCore.Qt.RightToLeft) | 46 | self.setLayoutDirection(QtCore.Qt.RightToLeft) |
696 | 38 | self.clicked.connect(self.on_clicked) | 47 | self.clicked.connect(self.on_clicked) |
697 | @@ -45,3 +54,10 @@ | |||
698 | 45 | if self.uri is not None: | 54 | if self.uri is not None: |
699 | 46 | uri = yield self.backend.build_signed_iri(self.uri) | 55 | uri = yield self.backend.build_signed_iri(self.uri) |
700 | 47 | qt.uri_hook(uri) | 56 | qt.uri_hook(uri) |
701 | 57 | |||
702 | 58 | |||
703 | 59 | class GetStorageButton(GoToWebButton): | ||
704 | 60 | """A specific GoToWebButton to get more storage.""" | ||
705 | 61 | |||
706 | 62 | legend = GET_MORE_STORAGE | ||
707 | 63 | uri = GET_STORAGE_LINK | ||
708 | 48 | 64 | ||
709 | === modified file 'ubuntuone/controlpanel/gui/qt/tests/test_addfolder.py' | |||
710 | --- ubuntuone/controlpanel/gui/qt/tests/test_addfolder.py 2012-03-09 13:44:53 +0000 | |||
711 | +++ ubuntuone/controlpanel/gui/qt/tests/test_addfolder.py 2012-03-19 21:32:18 +0000 | |||
712 | @@ -18,8 +18,6 @@ | |||
713 | 18 | 18 | ||
714 | 19 | """Tests for the AddFolderButton widget.""" | 19 | """Tests for the AddFolderButton widget.""" |
715 | 20 | 20 | ||
716 | 21 | import os | ||
717 | 22 | |||
718 | 23 | from twisted.internet import defer | 21 | from twisted.internet import defer |
719 | 24 | 22 | ||
720 | 25 | from ubuntuone.controlpanel.gui.tests import ( | 23 | from ubuntuone.controlpanel.gui.tests import ( |
721 | @@ -48,11 +46,10 @@ | |||
722 | 48 | @defer.inlineCallbacks | 46 | @defer.inlineCallbacks |
723 | 49 | def setUp(self): | 47 | def setUp(self): |
724 | 50 | yield super(AddFolderButtonTestCase, self).setUp() | 48 | yield super(AddFolderButtonTestCase, self).setUp() |
725 | 49 | self.created_folders = [] | ||
726 | 51 | self.patch(FakedFileDialog, 'response', gui.QtCore.QString('')) | 50 | self.patch(FakedFileDialog, 'response', gui.QtCore.QString('')) |
727 | 52 | self.patch(self.ui.backend, 'validate_path_for_folder', lambda p: True) | 51 | self.patch(self.ui.backend, 'validate_path_for_folder', lambda p: True) |
731 | 53 | old_home = os.environ['HOME'] | 52 | self.patch(self.ui, 'add_folder_func', self.add_folder) |
729 | 54 | os.environ['HOME'] = USER_HOME | ||
730 | 55 | self.addCleanup(lambda: os.environ.__setitem__('HOME', old_home)) | ||
732 | 56 | 53 | ||
733 | 57 | @defer.inlineCallbacks | 54 | @defer.inlineCallbacks |
734 | 58 | def assert_does_nothing(self, method_call): | 55 | def assert_does_nothing(self, method_call): |
735 | @@ -73,6 +70,18 @@ | |||
736 | 73 | # the folderCreated signal was not emitted | 70 | # the folderCreated signal was not emitted |
737 | 74 | self.assertEqual(self._called, False) | 71 | self.assertEqual(self._called, False) |
738 | 75 | 72 | ||
739 | 73 | def add_folder(self, folder_path): | ||
740 | 74 | """A dummy add folder func.""" | ||
741 | 75 | self.created_folders.append(folder_path) | ||
742 | 76 | return defer.succeed(None) | ||
743 | 77 | |||
744 | 78 | def test_default_add_folder_func(self): | ||
745 | 79 | """The add_folder_func is used.""" | ||
746 | 80 | folder = set_path_on_file_dialog() | ||
747 | 81 | yield self.ui.on_clicked() | ||
748 | 82 | |||
749 | 83 | self.assertEqual(self.created_folders, [folder]) | ||
750 | 84 | |||
751 | 76 | @defer.inlineCallbacks | 85 | @defer.inlineCallbacks |
752 | 77 | def test_add_folder_button_clicked_opens_file_chooser(self): | 86 | def test_add_folder_button_clicked_opens_file_chooser(self): |
753 | 78 | """When adding a new folder, the proper file chooser is raised.""" | 87 | """When adding a new folder, the proper file chooser is raised.""" |
754 | @@ -121,7 +130,7 @@ | |||
755 | 121 | self.assertEqual(FakedDialog.args, None) | 130 | self.assertEqual(FakedDialog.args, None) |
756 | 122 | self.assertEqual(FakedDialog.kwargs, None) | 131 | self.assertEqual(FakedDialog.kwargs, None) |
757 | 123 | # backend called | 132 | # backend called |
759 | 124 | self.assert_backend_called('create_folder', folder_path=folder) | 133 | self.assertEqual(self.created_folders, [folder]) |
760 | 125 | 134 | ||
761 | 126 | @defer.inlineCallbacks | 135 | @defer.inlineCallbacks |
762 | 127 | def test_calls_backend(self): | 136 | def test_calls_backend(self): |
763 | @@ -133,7 +142,7 @@ | |||
764 | 133 | self.assertEqual(FakedDialog.args, None) | 142 | self.assertEqual(FakedDialog.args, None) |
765 | 134 | self.assertEqual(FakedDialog.kwargs, None) | 143 | self.assertEqual(FakedDialog.kwargs, None) |
766 | 135 | # backend called | 144 | # backend called |
768 | 136 | self.assert_backend_called('create_folder', folder_path=folder) | 145 | self.assertEqual(self.created_folders, [folder]) |
769 | 137 | 146 | ||
770 | 138 | @defer.inlineCallbacks | 147 | @defer.inlineCallbacks |
771 | 139 | def test_emit_folder_created_on_success(self): | 148 | def test_emit_folder_created_on_success(self): |
772 | 140 | 149 | ||
773 | === modified file 'ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py' | |||
774 | --- ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py 2012-03-16 18:54:55 +0000 | |||
775 | +++ ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py 2012-03-19 21:32:18 +0000 | |||
776 | @@ -193,7 +193,7 @@ | |||
777 | 193 | def test_get_more_space_button(self): | 193 | def test_get_more_space_button(self): |
778 | 194 | """When clicking the get more GB button, the proper url is opened.""" | 194 | """When clicking the get more GB button, the proper url is opened.""" |
779 | 195 | self.assert_uri_hook_called(self.ui.ui.get_more_space_button, | 195 | self.assert_uri_hook_called(self.ui.ui.get_more_space_button, |
781 | 196 | gui.EDIT_SERVICES_LINK) | 196 | gui.GET_STORAGE_LINK) |
782 | 197 | 197 | ||
783 | 198 | def test_help_button(self): | 198 | def test_help_button(self): |
784 | 199 | """When clicking the help button, the proper url is opened.""" | 199 | """When clicking the help button, the proper url is opened.""" |
785 | 200 | 200 | ||
786 | === modified file 'ubuntuone/controlpanel/gui/qt/tests/test_folders.py' | |||
787 | --- ubuntuone/controlpanel/gui/qt/tests/test_folders.py 2012-03-19 13:47:56 +0000 | |||
788 | +++ ubuntuone/controlpanel/gui/qt/tests/test_folders.py 2012-03-19 21:32:18 +0000 | |||
789 | @@ -20,11 +20,14 @@ | |||
790 | 20 | import logging | 20 | import logging |
791 | 21 | import operator | 21 | import operator |
792 | 22 | import os | 22 | import os |
793 | 23 | import Queue | ||
794 | 24 | import shutil | ||
795 | 23 | 25 | ||
796 | 24 | from PyQt4 import QtGui | 26 | from PyQt4 import QtGui |
797 | 25 | from twisted.internet import defer | 27 | from twisted.internet import defer |
798 | 26 | from ubuntuone.devtools.handlers import MementoHandler | 28 | from ubuntuone.devtools.handlers import MementoHandler |
799 | 27 | 29 | ||
800 | 30 | from ubuntuone.controlpanel.tests import helper_fail | ||
801 | 28 | from ubuntuone.controlpanel.gui.tests import ( | 31 | from ubuntuone.controlpanel.gui.tests import ( |
802 | 29 | FAKE_VOLUMES_INFO, | 32 | FAKE_VOLUMES_INFO, |
803 | 30 | FAKE_VOLUMES_MINIMAL_INFO, | 33 | FAKE_VOLUMES_MINIMAL_INFO, |
804 | @@ -413,6 +416,8 @@ | |||
805 | 413 | 416 | ||
806 | 414 | def test_add_folder_button(self): | 417 | def test_add_folder_button(self): |
807 | 415 | """The 'add_folder_button' is visible by default.""" | 418 | """The 'add_folder_button' is visible by default.""" |
808 | 419 | self.assertEqual(self.ui.ui.add_folder_button.add_folder_func, | ||
809 | 420 | self.ui.backend.create_folder) | ||
810 | 416 | self.assertTrue(self.ui.ui.add_folder_button.isVisible()) | 421 | self.assertTrue(self.ui.ui.add_folder_button.isVisible()) |
811 | 417 | 422 | ||
812 | 418 | def test_check_settings_button(self): | 423 | def test_check_settings_button(self): |
813 | @@ -650,3 +655,204 @@ | |||
814 | 650 | 655 | ||
815 | 651 | class_ui = gui.RemoteFoldersPanel | 656 | class_ui = gui.RemoteFoldersPanel |
816 | 652 | faked_volumes = volumes_with_music_unsubscribed() | 657 | faked_volumes = volumes_with_music_unsubscribed() |
817 | 658 | |||
818 | 659 | |||
819 | 660 | class BaseLocalFoldersTestCase(BaseTestCase): | ||
820 | 661 | """Test suite for the class implementing the LocalFolders feature.""" | ||
821 | 662 | |||
822 | 663 | @defer.inlineCallbacks | ||
823 | 664 | def setUp(self): | ||
824 | 665 | self.path = 'not-existing-dir' | ||
825 | 666 | self.expected_size = self.build_test_dir(self.path) | ||
826 | 667 | self.queue = Queue.Queue() | ||
827 | 668 | yield super(BaseLocalFoldersTestCase, self).setUp() | ||
828 | 669 | |||
829 | 670 | def build_test_dir(self, dir_path): | ||
830 | 671 | """Build a testing directory hierarchy.""" | ||
831 | 672 | assert not os.path.exists(dir_path) | ||
832 | 673 | |||
833 | 674 | os.makedirs(dir_path) | ||
834 | 675 | self.addCleanup(shutil.rmtree, dir_path) | ||
835 | 676 | |||
836 | 677 | total_size = 0 | ||
837 | 678 | |||
838 | 679 | a_file = os.path.join(dir_path, 'test_file') | ||
839 | 680 | with open(a_file, 'wb') as f: | ||
840 | 681 | f.write('z' * 1000000) | ||
841 | 682 | |||
842 | 683 | total_size += os.path.getsize(a_file) | ||
843 | 684 | |||
844 | 685 | inner_dir = os.path.join(dir_path, 'test_dir') | ||
845 | 686 | os.mkdir(inner_dir) | ||
846 | 687 | |||
847 | 688 | other_file = os.path.join(dir_path, 'other_test_file') | ||
848 | 689 | with open(other_file, 'wb') as f: | ||
849 | 690 | f.write(' ' * 99999) | ||
850 | 691 | |||
851 | 692 | total_size += os.path.getsize(other_file) | ||
852 | 693 | |||
853 | 694 | empty_dir = os.path.join(dir_path, 'empty') | ||
854 | 695 | os.mkdir(empty_dir) | ||
855 | 696 | |||
856 | 697 | # add a symlink to confirm those are avoided | ||
857 | 698 | a_link = os.path.join(dir_path, 'some_link') | ||
858 | 699 | os.symlink(a_file, a_link) | ||
859 | 700 | |||
860 | 701 | return total_size | ||
861 | 702 | |||
862 | 703 | |||
863 | 704 | class CalculateSizeTestCase(BaseLocalFoldersTestCase): | ||
864 | 705 | """Test suite for the CalculateSize thread implementation.""" | ||
865 | 706 | |||
866 | 707 | @defer.inlineCallbacks | ||
867 | 708 | def setUp(self): | ||
868 | 709 | yield super(CalculateSizeTestCase, self).setUp() | ||
869 | 710 | self.ui = gui.CalculateSize(path_name=self.path, queue=self.queue) | ||
870 | 711 | self.patch(self.ui, 'start', lambda: None) | ||
871 | 712 | |||
872 | 713 | def test_creation(self): | ||
873 | 714 | """The created instance is correct.""" | ||
874 | 715 | self.assertEqual(self.ui.path_name, self.path) | ||
875 | 716 | self.assertEqual(self.ui.queue, self.queue) | ||
876 | 717 | self.assertTrue(self.ui.daemon) | ||
877 | 718 | |||
878 | 719 | def test_run(self): | ||
879 | 720 | """The run() method calculates the size for the given path.""" | ||
880 | 721 | self.ui.run() | ||
881 | 722 | |||
882 | 723 | path, size = self.queue.get(block=True, timeout=0.5) | ||
883 | 724 | |||
884 | 725 | self.assertEqual(path, self.path) | ||
885 | 726 | self.assertEqual(size, self.expected_size) | ||
886 | 727 | |||
887 | 728 | def test_run_handles_errors(self): | ||
888 | 729 | """The run() method handles errors.""" | ||
889 | 730 | self.patch(gui.os, 'walk', helper_fail) | ||
890 | 731 | self.ui.run() | ||
891 | 732 | |||
892 | 733 | self.assertRaises(Queue.Empty, self.queue.get, block=True, timeout=0.5) | ||
893 | 734 | |||
894 | 735 | |||
895 | 736 | class FakedCalculateSize(object): | ||
896 | 737 | """A faked CalculateSize thread.""" | ||
897 | 738 | |||
898 | 739 | def __init__(self, *args, **kwargs): | ||
899 | 740 | self.started = False | ||
900 | 741 | |||
901 | 742 | def start(self): | ||
902 | 743 | """Fake start.""" | ||
903 | 744 | self.started = True | ||
904 | 745 | |||
905 | 746 | |||
906 | 747 | class FolderItemTestCase(BaseLocalFoldersTestCase): | ||
907 | 748 | """Test suite for the FolderItem widget.""" | ||
908 | 749 | |||
909 | 750 | @defer.inlineCallbacks | ||
910 | 751 | def setUp(self): | ||
911 | 752 | yield super(FolderItemTestCase, self).setUp() | ||
912 | 753 | self.calculator = FakedCalculateSize(self.path, self.queue) | ||
913 | 754 | self.patch(gui, 'CalculateSize', lambda *a, **kw: self.calculator) | ||
914 | 755 | self.values = ['foo', 'bar'] | ||
915 | 756 | |||
916 | 757 | assert not self.calculator.started | ||
917 | 758 | |||
918 | 759 | def test_no_params(self): | ||
919 | 760 | """The creation with no params uses defaults.""" | ||
920 | 761 | item = gui.FolderItem() | ||
921 | 762 | |||
922 | 763 | self.assertEqual(item.text(gui.LOCAL_SUBSCRIPTION_COL), '') | ||
923 | 764 | self.assertEqual(item.text(gui.LOCAL_SPACE_COL), '') | ||
924 | 765 | self.assertEqual(item.path, None) | ||
925 | 766 | self.assertEqual(item.volume_id, None) | ||
926 | 767 | self.assertEqual(item.thread, None) | ||
927 | 768 | self.assertEqual(item.size, 0) | ||
928 | 769 | self.assertEqual(item.checkState(gui.LOCAL_SUBSCRIPTION_COL), | ||
929 | 770 | gui.UNCHECKED) | ||
930 | 771 | |||
931 | 772 | def test_values(self): | ||
932 | 773 | """The creation with only values.""" | ||
933 | 774 | item = gui.FolderItem(values=self.values) | ||
934 | 775 | |||
935 | 776 | self.assertEqual(item.text(gui.LOCAL_SUBSCRIPTION_COL), self.values[0]) | ||
936 | 777 | self.assertEqual(item.text(gui.LOCAL_SPACE_COL), self.values[1]) | ||
937 | 778 | self.assertEqual(item.path, None) | ||
938 | 779 | self.assertEqual(item.volume_id, None) | ||
939 | 780 | self.assertEqual(item.thread, None) | ||
940 | 781 | self.assertEqual(item.size, 0) | ||
941 | 782 | self.assertEqual(item.checkState(gui.LOCAL_SUBSCRIPTION_COL), | ||
942 | 783 | gui.UNCHECKED) | ||
943 | 784 | |||
944 | 785 | def test_path(self): | ||
945 | 786 | """The creation with only a path.""" | ||
946 | 787 | item = gui.FolderItem(path=self.path) | ||
947 | 788 | |||
948 | 789 | self.assertEqual(item.text(gui.LOCAL_SUBSCRIPTION_COL), '') | ||
949 | 790 | self.assertEqual(item.text(gui.LOCAL_SPACE_COL), '') | ||
950 | 791 | self.assertEqual(item.path, self.path) | ||
951 | 792 | self.assertEqual(item.volume_id, None) | ||
952 | 793 | self.assertEqual(item.thread, None) | ||
953 | 794 | self.assertEqual(item.size, 0) | ||
954 | 795 | self.assertEqual(item.checkState(gui.LOCAL_SUBSCRIPTION_COL), | ||
955 | 796 | gui.UNCHECKED) | ||
956 | 797 | |||
957 | 798 | def test_queue(self): | ||
958 | 799 | """The creation with only a queue.""" | ||
959 | 800 | item = gui.FolderItem(queue=self.queue) | ||
960 | 801 | |||
961 | 802 | self.assertEqual(item.text(gui.LOCAL_SUBSCRIPTION_COL), '') | ||
962 | 803 | self.assertEqual(item.text(gui.LOCAL_SPACE_COL), '') | ||
963 | 804 | self.assertEqual(item.path, None) | ||
964 | 805 | self.assertEqual(item.volume_id, None) | ||
965 | 806 | self.assertEqual(item.thread, None) | ||
966 | 807 | self.assertEqual(item.size, 0) | ||
967 | 808 | self.assertEqual(item.checkState(gui.LOCAL_SUBSCRIPTION_COL), | ||
968 | 809 | gui.UNCHECKED) | ||
969 | 810 | |||
970 | 811 | def test_volume_id(self): | ||
971 | 812 | """The creation with only a volume_id.""" | ||
972 | 813 | item = gui.FolderItem(volume_id='yadda') | ||
973 | 814 | |||
974 | 815 | self.assertEqual(item.text(gui.LOCAL_SUBSCRIPTION_COL), '') | ||
975 | 816 | self.assertEqual(item.text(gui.LOCAL_SPACE_COL), '') | ||
976 | 817 | self.assertEqual(item.path, None) | ||
977 | 818 | self.assertEqual(item.volume_id, 'yadda') | ||
978 | 819 | self.assertEqual(item.thread, None) | ||
979 | 820 | self.assertEqual(item.size, 0) | ||
980 | 821 | self.assertEqual(item.checkState(gui.LOCAL_SUBSCRIPTION_COL), | ||
981 | 822 | gui.UNCHECKED) | ||
982 | 823 | |||
983 | 824 | def test_path_and_volume_id(self): | ||
984 | 825 | """The creation with only a volume_id.""" | ||
985 | 826 | item = gui.FolderItem(path=self.path, volume_id='yadda') | ||
986 | 827 | |||
987 | 828 | self.assertEqual(item.text(gui.LOCAL_SUBSCRIPTION_COL), '') | ||
988 | 829 | self.assertEqual(item.text(gui.LOCAL_SPACE_COL), '') | ||
989 | 830 | self.assertEqual(item.path, self.path) | ||
990 | 831 | self.assertEqual(item.volume_id, 'yadda') | ||
991 | 832 | self.assertEqual(item.thread, None) | ||
992 | 833 | self.assertEqual(item.size, 0) | ||
993 | 834 | self.assertEqual(item.checkState(gui.LOCAL_SUBSCRIPTION_COL), | ||
994 | 835 | gui.CHECKED) | ||
995 | 836 | |||
996 | 837 | def test_path_and_queue(self): | ||
997 | 838 | """The creation with only a volume_id.""" | ||
998 | 839 | item = gui.FolderItem(path=self.path, queue=self.queue) | ||
999 | 840 | |||
1000 | 841 | self.assertEqual(item.text(gui.LOCAL_SUBSCRIPTION_COL), '') | ||
1001 | 842 | self.assertEqual(item.text(gui.LOCAL_SPACE_COL), '') | ||
1002 | 843 | self.assertEqual(item.path, self.path) | ||
1003 | 844 | self.assertEqual(item.volume_id, None) | ||
1004 | 845 | self.assertEqual(item.thread, self.calculator) | ||
1005 | 846 | self.assertEqual(item.size, None) | ||
1006 | 847 | self.assertEqual(item.checkState(gui.LOCAL_SUBSCRIPTION_COL), | ||
1007 | 848 | gui.UNCHECKED) | ||
1008 | 849 | |||
1009 | 850 | self.assertTrue(self.calculator.started) | ||
1010 | 851 | |||
1011 | 852 | |||
1012 | 853 | class LocalFoldersPanelTestCase(UbuntuOneBinTestCase): | ||
1013 | 854 | """Test suite for the LocalFoldersPanel widget.""" | ||
1014 | 855 | |||
1015 | 856 | class_ui = gui.LocalFoldersPanel | ||
1016 | 857 | |||
1017 | 858 | # TODO: add the test suite (LP: #959690). | ||
1018 | 653 | 859 | ||
1019 | === modified file 'ubuntuone/controlpanel/gui/qt/tests/test_gotoweb.py' | |||
1020 | --- ubuntuone/controlpanel/gui/qt/tests/test_gotoweb.py 2012-02-06 15:23:27 +0000 | |||
1021 | +++ ubuntuone/controlpanel/gui/qt/tests/test_gotoweb.py 2012-03-19 21:32:18 +0000 | |||
1022 | @@ -18,8 +18,6 @@ | |||
1023 | 18 | 18 | ||
1024 | 19 | """Tests for the GoToWebButton widget.""" | 19 | """Tests for the GoToWebButton widget.""" |
1025 | 20 | 20 | ||
1026 | 21 | from twisted.internet import defer | ||
1027 | 22 | |||
1028 | 23 | from ubuntuone.controlpanel.gui import qt | 21 | from ubuntuone.controlpanel.gui import qt |
1029 | 24 | from ubuntuone.controlpanel.gui.qt import gotoweb as gui | 22 | from ubuntuone.controlpanel.gui.qt import gotoweb as gui |
1030 | 25 | from ubuntuone.controlpanel.gui.qt.tests import ( | 23 | from ubuntuone.controlpanel.gui.qt.tests import ( |
1031 | @@ -32,9 +30,16 @@ | |||
1032 | 32 | 30 | ||
1033 | 33 | class_ui = gui.GoToWebButton | 31 | class_ui = gui.GoToWebButton |
1034 | 34 | 32 | ||
1038 | 35 | @defer.inlineCallbacks | 33 | def test_uri_default(self): |
1039 | 36 | def setUp(self): | 34 | """The uri uses the default.""" |
1040 | 37 | yield super(GoToWebButtonTestCase, self).setUp() | 35 | self.assertEqual(self.ui.uri, self.class_ui.uri) |
1041 | 36 | |||
1042 | 37 | def test_text_default(self): | ||
1043 | 38 | """The text uses the default.""" | ||
1044 | 39 | if self.class_ui.legend is not None: | ||
1045 | 40 | self.assertEqual(self.ui.text(), self.class_ui.legend) | ||
1046 | 41 | else: | ||
1047 | 42 | self.assertEqual(self.ui.text(), '') | ||
1048 | 38 | 43 | ||
1049 | 39 | def test_uri_can_be_set(self): | 44 | def test_uri_can_be_set(self): |
1050 | 40 | """The uri can be set.""" | 45 | """The uri can be set.""" |
1051 | @@ -69,3 +74,17 @@ | |||
1052 | 69 | self.ui.click() | 74 | self.ui.click() |
1053 | 70 | 75 | ||
1054 | 71 | self.assertEqual(self._called, False) | 76 | self.assertEqual(self._called, False) |
1055 | 77 | |||
1056 | 78 | |||
1057 | 79 | class GetStorageButtonTestCase(GoToWebButtonTestCase): | ||
1058 | 80 | """The test suite for the GetStorageButton widget.""" | ||
1059 | 81 | |||
1060 | 82 | class_ui = gui.GetStorageButton | ||
1061 | 83 | |||
1062 | 84 | def test_uri(self): | ||
1063 | 85 | """The default uri is correct.""" | ||
1064 | 86 | self.assertEqual(self.ui.uri, gui.GET_STORAGE_LINK) | ||
1065 | 87 | |||
1066 | 88 | def test_text(self): | ||
1067 | 89 | """The default legend is correct.""" | ||
1068 | 90 | self.assertEqual(self.ui.text(), gui.GET_MORE_STORAGE) | ||
1069 | 72 | 91 | ||
1070 | === modified file 'ubuntuone/controlpanel/gui/qt/tests/test_wizard.py' | |||
1071 | --- ubuntuone/controlpanel/gui/qt/tests/test_wizard.py 2012-03-16 21:15:09 +0000 | |||
1072 | +++ ubuntuone/controlpanel/gui/qt/tests/test_wizard.py 2012-03-19 21:32:18 +0000 | |||
1073 | @@ -110,10 +110,6 @@ | |||
1074 | 110 | panel_class = gui.RemoteFoldersPanel | 110 | panel_class = gui.RemoteFoldersPanel |
1075 | 111 | sub_title = gui.CLOUD_TO_COMPUTER_SUBTITLE | 111 | sub_title = gui.CLOUD_TO_COMPUTER_SUBTITLE |
1076 | 112 | 112 | ||
1077 | 113 | def test_is_final(self): | ||
1078 | 114 | """The page is not final.""" | ||
1079 | 115 | self.assertTrue(self.ui.isFinalPage()) | ||
1080 | 116 | |||
1081 | 117 | def test_folder_panel_shows_remote_folders_only(self): | 113 | def test_folder_panel_shows_remote_folders_only(self): |
1082 | 118 | """The FolderPanel shows only remote folders.""" | 114 | """The FolderPanel shows only remote folders.""" |
1083 | 119 | self.assertTrue(self.ui.panel.remote_folders) | 115 | self.assertTrue(self.ui.panel.remote_folders) |
1084 | @@ -126,6 +122,19 @@ | |||
1085 | 126 | panel_class = gui.PreferencesPanel | 122 | panel_class = gui.PreferencesPanel |
1086 | 127 | 123 | ||
1087 | 128 | 124 | ||
1088 | 125 | class ComputerToCloudPageTestCase(UbuntuOnePageTestCase): | ||
1089 | 126 | """Test the ComputerToCloudPage wizard page.""" | ||
1090 | 127 | |||
1091 | 128 | class_ui = gui.ComputerToCloudPage | ||
1092 | 129 | main_title = gui.COMPUTER_TO_CLOUD_TITLE | ||
1093 | 130 | panel_class = gui.LocalFoldersPanel | ||
1094 | 131 | sub_title = gui.COMPUTER_TO_CLOUD_SUBTITLE | ||
1095 | 132 | |||
1096 | 133 | def test_is_final(self): | ||
1097 | 134 | """The page is not final.""" | ||
1098 | 135 | self.assertTrue(self.ui.isFinalPage()) | ||
1099 | 136 | |||
1100 | 137 | |||
1101 | 129 | class UbuntuOneWizardTestCase(BaseTestCase): | 138 | class UbuntuOneWizardTestCase(BaseTestCase): |
1102 | 130 | """Test the UbuntuOneWizard widget.""" | 139 | """Test the UbuntuOneWizard widget.""" |
1103 | 131 | 140 | ||
1104 | @@ -266,16 +275,33 @@ | |||
1105 | 266 | class UbuntuOneWizardCloudToComputerTestCase(UbuntuOneWizardSignInTestCase): | 275 | class UbuntuOneWizardCloudToComputerTestCase(UbuntuOneWizardSignInTestCase): |
1106 | 267 | """Test the CloudToComputerPage wizard page.""" | 276 | """Test the CloudToComputerPage wizard page.""" |
1107 | 268 | 277 | ||
1110 | 269 | buttons = {'FinishButton': | 278 | buttons = {'NextButton': (None, 'currentIdChanged', (3,))} |
1109 | 270 | (None, 'finished', (gui.QtGui.QDialog.Accepted,))} | ||
1111 | 271 | page_name = 'cloud_folders' | 279 | page_name = 'cloud_folders' |
1112 | 272 | stage_name = 'folders' | 280 | stage_name = 'folders' |
1113 | 273 | 281 | ||
1114 | 282 | |||
1115 | 283 | class UbuntuOneWizardSettingsTestCase(UbuntuOneWizardSignInTestCase): | ||
1116 | 284 | """Test the CloudToComputerPage wizard page.""" | ||
1117 | 285 | |||
1118 | 286 | buttons = {'BackButton': (None, 'currentIdChanged', (0,))} | ||
1119 | 287 | page_name = 'settings' | ||
1120 | 288 | stage_name = 'folders' | ||
1121 | 289 | |||
1122 | 290 | |||
1123 | 291 | class UbuntuOneWizardComputerToCloudTestCase(UbuntuOneWizardSignInTestCase): | ||
1124 | 292 | """Test the CloudToComputerPage wizard page.""" | ||
1125 | 293 | |||
1126 | 294 | buttons = { | ||
1127 | 295 | 'FinishButton': (None, 'finished', (gui.QtGui.QDialog.Accepted,)), | ||
1128 | 296 | 'BackButton': (None, 'currentIdChanged', (0,)), | ||
1129 | 297 | } | ||
1130 | 298 | page_name = 'local_folders' | ||
1131 | 299 | stage_name = 'sync' | ||
1132 | 300 | |||
1133 | 274 | def test_done_rejected(self): | 301 | def test_done_rejected(self): |
1134 | 275 | """When the wizard is closed on the final page, emit rejected.""" | 302 | """When the wizard is closed on the final page, emit rejected.""" |
1135 | 276 | self.ui.finished.connect(self._set_called) | 303 | self.ui.finished.connect(self._set_called) |
1136 | 277 | 304 | ||
1137 | 278 | self.ui._next_id = self.ui.pages[self.ui.cloud_folders_page] | ||
1138 | 279 | assert self.ui.page(self.ui.currentId()).isFinalPage() | 305 | assert self.ui.page(self.ui.currentId()).isFinalPage() |
1139 | 280 | self.ui.done(gui.QtGui.QDialog.Rejected) | 306 | self.ui.done(gui.QtGui.QDialog.Rejected) |
1140 | 281 | 307 | ||
1141 | @@ -286,14 +312,6 @@ | |||
1142 | 286 | # does not apply to this page | 312 | # does not apply to this page |
1143 | 287 | 313 | ||
1144 | 288 | 314 | ||
1145 | 289 | class UbuntuOneWizardSettingsTestCase(UbuntuOneWizardSignInTestCase): | ||
1146 | 290 | """Test the CloudToComputerPage wizard page.""" | ||
1147 | 291 | |||
1148 | 292 | buttons = {'BackButton': (None, 'currentIdChanged', (0,))} | ||
1149 | 293 | page_name = 'settings' | ||
1150 | 294 | stage_name = 'folders' | ||
1151 | 295 | |||
1152 | 296 | |||
1153 | 297 | class UbuntuOneWizardLoginTestCase(UbuntuOneWizardTestCase): | 315 | class UbuntuOneWizardLoginTestCase(UbuntuOneWizardTestCase): |
1154 | 298 | """Test the login through the wizard.""" | 316 | """Test the login through the wizard.""" |
1155 | 299 | 317 | ||
1156 | 300 | 318 | ||
1157 | === modified file 'ubuntuone/controlpanel/gui/qt/wizard.py' | |||
1158 | --- ubuntuone/controlpanel/gui/qt/wizard.py 2012-03-16 21:15:09 +0000 | |||
1159 | +++ ubuntuone/controlpanel/gui/qt/wizard.py 2012-03-19 21:32:18 +0000 | |||
1160 | @@ -34,10 +34,13 @@ | |||
1161 | 34 | ARE_YOU_SURE_YES, | 34 | ARE_YOU_SURE_YES, |
1162 | 35 | CLOUD_TO_COMPUTER_SUBTITLE, | 35 | CLOUD_TO_COMPUTER_SUBTITLE, |
1163 | 36 | CLOUD_TO_COMPUTER_TITLE, | 36 | CLOUD_TO_COMPUTER_TITLE, |
1164 | 37 | COMPUTER_TO_CLOUD_SUBTITLE, | ||
1165 | 38 | COMPUTER_TO_CLOUD_TITLE, | ||
1166 | 37 | UBUNTUONE_LINK, | 39 | UBUNTUONE_LINK, |
1167 | 38 | ) | 40 | ) |
1168 | 39 | from ubuntuone.controlpanel.gui.qt.folders import ( | 41 | from ubuntuone.controlpanel.gui.qt.folders import ( |
1169 | 40 | RemoteFoldersPanel, | 42 | RemoteFoldersPanel, |
1170 | 43 | LocalFoldersPanel, | ||
1171 | 41 | ) | 44 | ) |
1172 | 42 | from ubuntuone.controlpanel.gui.qt.preferences import PreferencesPanel | 45 | from ubuntuone.controlpanel.gui.qt.preferences import PreferencesPanel |
1173 | 43 | from ubuntuone.controlpanel.gui.qt.signin import SignInPanel | 46 | from ubuntuone.controlpanel.gui.qt.signin import SignInPanel |
1174 | @@ -109,7 +112,6 @@ | |||
1175 | 109 | main_title = CLOUD_TO_COMPUTER_TITLE | 112 | main_title = CLOUD_TO_COMPUTER_TITLE |
1176 | 110 | panel_class = RemoteFoldersPanel | 113 | panel_class = RemoteFoldersPanel |
1177 | 111 | sub_title = CLOUD_TO_COMPUTER_SUBTITLE | 114 | sub_title = CLOUD_TO_COMPUTER_SUBTITLE |
1178 | 112 | is_final = True | ||
1179 | 113 | 115 | ||
1180 | 114 | def __init__(self, *args, **kwargs): | 116 | def __init__(self, *args, **kwargs): |
1181 | 115 | super(CloudToComputerPage, self).__init__(*args, **kwargs) | 117 | super(CloudToComputerPage, self).__init__(*args, **kwargs) |
1182 | @@ -122,6 +124,15 @@ | |||
1183 | 122 | panel_class = PreferencesPanel | 124 | panel_class = PreferencesPanel |
1184 | 123 | 125 | ||
1185 | 124 | 126 | ||
1186 | 127 | class ComputerToCloudPage(UbuntuOnePage): | ||
1187 | 128 | """The page to choose local folders to sync remotly.""" | ||
1188 | 129 | |||
1189 | 130 | is_final = True | ||
1190 | 131 | main_title = COMPUTER_TO_CLOUD_TITLE | ||
1191 | 132 | panel_class = LocalFoldersPanel | ||
1192 | 133 | sub_title = COMPUTER_TO_CLOUD_SUBTITLE | ||
1193 | 134 | |||
1194 | 135 | |||
1195 | 125 | class UbuntuOneWizard(cache.Cache, QtGui.QWizard): | 136 | class UbuntuOneWizard(cache.Cache, QtGui.QWizard): |
1196 | 126 | """The Ubuntu One wizard.""" | 137 | """The Ubuntu One wizard.""" |
1197 | 127 | 138 | ||
1198 | @@ -160,6 +171,10 @@ | |||
1199 | 160 | self.settings_page = SettingsPage() | 171 | self.settings_page = SettingsPage() |
1200 | 161 | self.addPage(self.settings_page) | 172 | self.addPage(self.settings_page) |
1201 | 162 | 173 | ||
1202 | 174 | # computer to cloud | ||
1203 | 175 | self.local_folders_page = ComputerToCloudPage() | ||
1204 | 176 | self.addPage(self.local_folders_page) | ||
1205 | 177 | |||
1206 | 163 | self._next_id = self.pages[self.signin_page] | 178 | self._next_id = self.pages[self.signin_page] |
1207 | 164 | self.next() | 179 | self.next() |
1208 | 165 | 180 | ||
1209 | @@ -187,16 +202,22 @@ | |||
1210 | 187 | stage = self.side_widget.signin_stage | 202 | stage = self.side_widget.signin_stage |
1211 | 188 | self._next_id = self.pages[self.cloud_folders_page] | 203 | self._next_id = self.pages[self.cloud_folders_page] |
1212 | 189 | elif page is self.cloud_folders_page: | 204 | elif page is self.cloud_folders_page: |
1214 | 190 | button_layout = [self.Stretch, self.FinishButton] | 205 | button_layout = [self.Stretch, self.NextButton] |
1215 | 191 | button = self.cloud_folders_page.panel.ui.check_settings_button | 206 | button = self.cloud_folders_page.panel.ui.check_settings_button |
1217 | 192 | button_to = self.button(self.FinishButton) | 207 | button_to = self.button(self.NextButton) |
1218 | 193 | stage = self.side_widget.folders_stage | 208 | stage = self.side_widget.folders_stage |
1219 | 209 | self._next_id = self.pages[self.local_folders_page] | ||
1220 | 194 | elif page is self.settings_page: | 210 | elif page is self.settings_page: |
1222 | 195 | button_layout = [self.BackButton, self.Stretch] | 211 | button_layout = [self.Stretch, self.BackButton] |
1223 | 196 | button = self.settings_page.panel.ui.apply_changes_button | 212 | button = self.settings_page.panel.ui.apply_changes_button |
1224 | 197 | button_to = self.button(self.BackButton) | 213 | button_to = self.button(self.BackButton) |
1225 | 198 | stage = self.side_widget.folders_stage | 214 | stage = self.side_widget.folders_stage |
1226 | 199 | self._next_id = self.pages[self.cloud_folders_page] | 215 | self._next_id = self.pages[self.cloud_folders_page] |
1227 | 216 | elif page is self.local_folders_page: | ||
1228 | 217 | button_layout = [self.Stretch, self.BackButton, self.FinishButton] | ||
1229 | 218 | button = self.local_folders_page.panel.ui.add_folder_button | ||
1230 | 219 | button_to = self.button(self.BackButton) | ||
1231 | 220 | stage = self.side_widget.sync_stage | ||
1232 | 200 | else: | 221 | else: |
1233 | 201 | logger.error('UbuntuOneWizard.initializePage was called with an' | 222 | logger.error('UbuntuOneWizard.initializePage was called with an' |
1234 | 202 | 'unknown page: %r (page_id was %r).', page, page_id) | 223 | 'unknown page: %r (page_id was %r).', page, page_id) |
1235 | @@ -217,7 +238,7 @@ | |||
1236 | 217 | """Called clean up 'page_id' just before the user leaves it.""" | 238 | """Called clean up 'page_id' just before the user leaves it.""" |
1237 | 218 | page = self.page(page_id) | 239 | page = self.page(page_id) |
1238 | 219 | logger.debug('UbuntuOneWizard.cleanupPage: page is %r.', page) | 240 | logger.debug('UbuntuOneWizard.cleanupPage: page is %r.', page) |
1240 | 220 | if page is self.settings_page: | 241 | if page is self.settings_page or page is self.local_folders_page: |
1241 | 221 | self.initializePage(self.pages[self.cloud_folders_page]) | 242 | self.initializePage(self.pages[self.cloud_folders_page]) |
1242 | 222 | 243 | ||
1243 | 223 | def nextId(self): | 244 | def nextId(self): |
1244 | @@ -257,8 +278,13 @@ | |||
1245 | 257 | 278 | ||
1246 | 258 | def done(self, result): | 279 | def done(self, result): |
1247 | 259 | """The main window is being closed, call any custom callback.""" | 280 | """The main window is being closed, call any custom callback.""" |
1250 | 260 | if (result == QtGui.QDialog.Rejected and | 281 | if result == QtGui.QDialog.Accepted: |
1251 | 261 | not self.page(self.currentId()).isFinalPage()): | 282 | parent_done = super(UbuntuOneWizard, self).done |
1252 | 283 | f = lambda: parent_done(QtGui.QDialog.Accepted) | ||
1253 | 284 | self.local_folders_page.panel.changesApplied.connect(f) | ||
1254 | 285 | # commit local_folders_page's changes | ||
1255 | 286 | self.local_folders_page.panel.apply_changes() | ||
1256 | 287 | elif not self.page(self.currentId()).isFinalPage(): | ||
1257 | 262 | response = self.confirm_dialog.exec_() | 288 | response = self.confirm_dialog.exec_() |
1258 | 263 | if response == QtGui.QDialog.Accepted: | 289 | if response == QtGui.QDialog.Accepted: |
1259 | 264 | logger.warning('UbuntuOneWizard: user canceled setup.') | 290 | logger.warning('UbuntuOneWizard: user canceled setup.') |
1260 | 265 | 291 | ||
1261 | === modified file 'ubuntuone/controlpanel/tests/__init__.py' | |||
1262 | --- ubuntuone/controlpanel/tests/__init__.py 2011-11-21 13:32:44 +0000 | |||
1263 | +++ ubuntuone/controlpanel/tests/__init__.py 2012-03-19 21:32:18 +0000 | |||
1264 | @@ -334,6 +334,15 @@ | |||
1265 | 334 | ] | 334 | ] |
1266 | 335 | 335 | ||
1267 | 336 | 336 | ||
1268 | 337 | class CustomError(Exception): | ||
1269 | 338 | """Custom error for tests.""" | ||
1270 | 339 | |||
1271 | 340 | |||
1272 | 341 | def helper_fail(*a, **kw): | ||
1273 | 342 | """Helper to raise an exception, usually used when monkey-patching.""" | ||
1274 | 343 | raise CustomError((a, kw)) | ||
1275 | 344 | |||
1276 | 345 | |||
1277 | 337 | class TestCase(BaseTestCase): | 346 | class TestCase(BaseTestCase): |
1278 | 338 | """Basics for testing.""" | 347 | """Basics for testing.""" |
1279 | 339 | 348 | ||
1280 | 340 | 349 | ||
1281 | === modified file 'ubuntuone/controlpanel/tests/test_login_client.py' | |||
1282 | --- ubuntuone/controlpanel/tests/test_login_client.py 2011-10-24 21:48:27 +0000 | |||
1283 | +++ ubuntuone/controlpanel/tests/test_login_client.py 2012-03-19 21:32:18 +0000 | |||
1284 | @@ -21,11 +21,7 @@ | |||
1285 | 21 | from twisted.internet import defer | 21 | from twisted.internet import defer |
1286 | 22 | 22 | ||
1287 | 23 | from ubuntuone.controlpanel import login_client | 23 | from ubuntuone.controlpanel import login_client |
1293 | 24 | from ubuntuone.controlpanel.tests import TestCase, TOKEN | 24 | from ubuntuone.controlpanel.tests import CustomError, TestCase, TOKEN |
1289 | 25 | |||
1290 | 26 | |||
1291 | 27 | class CustomError(Exception): | ||
1292 | 28 | """Custom error for tests.""" | ||
1294 | 29 | 25 | ||
1295 | 30 | 26 | ||
1296 | 31 | class FakedCredentialsManagementTool(object): | 27 | class FakedCredentialsManagementTool(object): |
1297 | 32 | 28 | ||
1298 | === modified file 'ubuntuone/controlpanel/tests/test_sd_client.py' | |||
1299 | --- ubuntuone/controlpanel/tests/test_sd_client.py 2012-01-26 13:16:17 +0000 | |||
1300 | +++ ubuntuone/controlpanel/tests/test_sd_client.py 2012-03-19 21:32:18 +0000 | |||
1301 | @@ -32,7 +32,7 @@ | |||
1302 | 32 | from ubuntuone.syncdaemon.interaction_interfaces import bool_str | 32 | from ubuntuone.syncdaemon.interaction_interfaces import bool_str |
1303 | 33 | 33 | ||
1304 | 34 | from ubuntuone.controlpanel import sd_client | 34 | from ubuntuone.controlpanel import sd_client |
1306 | 35 | from ubuntuone.controlpanel.tests import TestCase | 35 | from ubuntuone.controlpanel.tests import CustomError, TestCase |
1307 | 36 | 36 | ||
1308 | 37 | # Instance of 'SyncDaemonTool' has no 'foo' member | 37 | # Instance of 'SyncDaemonTool' has no 'foo' member |
1309 | 38 | # pylint: disable=E1101 | 38 | # pylint: disable=E1101 |
1310 | @@ -41,10 +41,6 @@ | |||
1311 | 41 | SAMPLE_LIMITS = {'upload': 999, 'download': 838} | 41 | SAMPLE_LIMITS = {'upload': 999, 'download': 838} |
1312 | 42 | 42 | ||
1313 | 43 | 43 | ||
1314 | 44 | class CustomError(Exception): | ||
1315 | 45 | """Custom error for tests.""" | ||
1316 | 46 | |||
1317 | 47 | |||
1318 | 48 | class FakedSyncDaemonTool(object): | 44 | class FakedSyncDaemonTool(object): |
1319 | 49 | """Fake the SyncDaemonTool.""" | 45 | """Fake the SyncDaemonTool.""" |
1320 | 50 | 46 |
It all works as expected!
Code looks good, but it does use new style and old style formatting: The problem is that while new style formatting has an awesome syntax, it is reportedly much slower than the old style, *and* it may tie us to a newer Python than we want without good reason.
Old style formatting is not scheduled to ever disappear from the language so I feel we should stick with that, at least until the performance problems are solved, and everyone is on a python that supports it, but maybe just forever.