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


Looks just like trunk.