Merge lp:~nataliabidart/ubuntu/oneiric/ubuntuone-control-panel/ubuntuone-control-panel-2.0.0 into lp:ubuntu/oneiric/ubuntuone-control-panel

Proposed by Natalia Bidart
Status: Merged
Merged at revision: 33
Proposed branch: lp:~nataliabidart/ubuntu/oneiric/ubuntuone-control-panel/ubuntuone-control-panel-2.0.0
Merge into: lp:ubuntu/oneiric/ubuntuone-control-panel
Diff against target: 30030 lines (+2419/-25703)
78 files modified
MANIFEST (+0/-140)
PKG-INFO (+2/-21)
bin/ubuntuone-control-panel-qt (+10/-1)
data/gtk/overview.ui (+4/-29)
data/gtk/services.ui (+16/-86)
data/qt/account.ui (+23/-2)
data/qt/controlpanel.ui (+228/-191)
data/qt/images.qrc (+1/-0)
data/qt/preferences.ui (+3/-3)
data/qt/signin.ui (+203/-0)
data/qt/ubuntuone.qss (+27/-5)
debian/changelog (+29/-0)
debian/control (+7/-7)
debian/ubuntuone-control-panel-gtk.install (+0/-1)
docs/ubuntuone-control-panel-gtk.1 (+2/-2)
po/POTFILES.in (+0/-1)
po/ubuntuone-control-panel.pot (+0/-486)
setup.py (+2/-2)
ubuntuone-control-panel-gtk.desktop.in (+0/-11)
ubuntuone-control-panel.in (+1/-1)
ubuntuone/controlpanel/backend.py (+24/-20)
ubuntuone/controlpanel/cache.py (+50/-0)
ubuntuone/controlpanel/dbus_service.py (+0/-40)
ubuntuone/controlpanel/dbustests/test_dbus_service.py (+3/-34)
ubuntuone/controlpanel/gui/__init__.py (+5/-5)
ubuntuone/controlpanel/gui/gtk/gui.py (+9/-12)
ubuntuone/controlpanel/gui/gtk/tests/__init__.py (+3/-3)
ubuntuone/controlpanel/gui/gtk/tests/test_gui_basic.py (+9/-1)
ubuntuone/controlpanel/gui/qt/__init__.py (+57/-2)
ubuntuone/controlpanel/gui/qt/account.py (+3/-0)
ubuntuone/controlpanel/gui/qt/addfolder.py (+11/-9)
ubuntuone/controlpanel/gui/qt/controlpanel.py (+73/-30)
ubuntuone/controlpanel/gui/qt/device.py (+15/-6)
ubuntuone/controlpanel/gui/qt/devices.py (+12/-7)
ubuntuone/controlpanel/gui/qt/filesyncstatus.py (+7/-8)
ubuntuone/controlpanel/gui/qt/folders.py (+25/-11)
ubuntuone/controlpanel/gui/qt/gotoweb.py (+19/-5)
ubuntuone/controlpanel/gui/qt/gui.py (+28/-5)
ubuntuone/controlpanel/gui/qt/loadingoverlay.py (+6/-4)
ubuntuone/controlpanel/gui/qt/main/linux.py (+4/-6)
ubuntuone/controlpanel/gui/qt/main/windows.py (+8/-11)
ubuntuone/controlpanel/gui/qt/preferences.py (+2/-0)
ubuntuone/controlpanel/gui/qt/signin.py (+89/-0)
ubuntuone/controlpanel/gui/qt/systray.py (+68/-0)
ubuntuone/controlpanel/gui/qt/tests/__init__.py (+93/-33)
ubuntuone/controlpanel/gui/qt/tests/test_account.py (+4/-9)
ubuntuone/controlpanel/gui/qt/tests/test_addfolder.py (+24/-24)
ubuntuone/controlpanel/gui/qt/tests/test_common.py (+210/-0)
ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py (+129/-24)
ubuntuone/controlpanel/gui/qt/tests/test_device.py (+20/-18)
ubuntuone/controlpanel/gui/qt/tests/test_devices.py (+12/-7)
ubuntuone/controlpanel/gui/qt/tests/test_folders.py (+27/-38)
ubuntuone/controlpanel/gui/qt/tests/test_gotoweb.py (+54/-2)
ubuntuone/controlpanel/gui/qt/tests/test_gui.py (+7/-0)
ubuntuone/controlpanel/gui/qt/tests/test_signin.py (+168/-0)
ubuntuone/controlpanel/gui/qt/tests/test_start.py (+91/-0)
ubuntuone/controlpanel/gui/qt/tests/test_systray.py (+103/-0)
ubuntuone/controlpanel/gui/qt/tests/test_ubuntuonebin.py (+20/-10)
ubuntuone/controlpanel/gui/qt/ubuntuonebin.py (+19/-10)
ubuntuone/controlpanel/gui/qt/ui/account_ui.py (+0/-84)
ubuntuone/controlpanel/gui/qt/ui/controlpanel_ui.py (+0/-208)
ubuntuone/controlpanel/gui/qt/ui/device_ui.py (+0/-46)
ubuntuone/controlpanel/gui/qt/ui/devices_ui.py (+0/-71)
ubuntuone/controlpanel/gui/qt/ui/filesyncstatus_ui.py (+0/-48)
ubuntuone/controlpanel/gui/qt/ui/folders_ui.py (+0/-90)
ubuntuone/controlpanel/gui/qt/ui/images_rc.py (+0/-23506)
ubuntuone/controlpanel/gui/qt/ui/loadingoverlay_ui.py (+0/-59)
ubuntuone/controlpanel/gui/qt/ui/mainwindow_ui.py (+0/-54)
ubuntuone/controlpanel/gui/qt/ui/preferences_ui.py (+0/-115)
ubuntuone/controlpanel/gui/tests/__init__.py (+4/-2)
ubuntuone/controlpanel/gui/tests/test_url_sign.py (+2/-2)
ubuntuone/controlpanel/logger.py (+5/-1)
ubuntuone/controlpanel/replication_client.py (+1/-2)
ubuntuone/controlpanel/tests/test_backend.py (+88/-31)
ubuntuone/controlpanel/tests/test_cache.py (+58/-0)
ubuntuone/controlpanel/web_client/tests/__init__.py (+19/-0)
ubuntuone/controlpanel/web_client/tests/test_txwebclient.py (+155/-0)
ubuntuone/controlpanel/web_client/txwebclient.py (+18/-1)
To merge this branch: bzr merge lp:~nataliabidart/ubuntu/oneiric/ubuntuone-control-panel/ubuntuone-control-panel-2.0.0
Reviewer Review Type Date Requested Status
Ubuntu Sponsors Pending
Review via email: mp+77034@code.launchpad.net

Description of the change

  * New upstream release:
    [ Alejandro J. Cura <email address hidden>]
      - Do not throw a webclient error when closing
        (LP: #845105).
    [ Natalia B. Bidart <email address hidden> ]
      - Removed all code related to Bookmarks (LP: #850142).
      - Replaces references to "Evolution" by "Thunderbird" (LP: #849494).
    [ Rodney Dawes <email address hidden> ]
      - Don't install a .desktop file for control panel
        (part of LP: #838778).
      - Point the indicator/Unity API at the installer .desktop file
        (part of LP: #838778).
      - Set the WMCLASS so Unity will fall back properly
        (part of LP: #838778).
      - Fix a few grammar mistakes (LP: #835093).
      - Don't show the "Get NGB free!" label on "Join now" button at all
        (LP: #819955).
  * debian/control:
    - ubuntuone-control-panel-gtk depends now on ubuntuone-installer >= 2.0.0.
    - require ubuntuone-client >= 2.0.0.
    - require ubuntu-sso-client >= 1.4.0.
    - no longer install a .desktop file (will be installed by ubuntuone-installer).

To post a comment you must log in.
Revision history for this message
Sebastien Bacher (seb128) wrote :

Thank you for your work

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== removed file 'MANIFEST'
--- MANIFEST 2011-08-12 19:12:08 +0000
+++ MANIFEST 1970-01-01 00:00:00 +0000
@@ -1,140 +0,0 @@
1# file GENERATED by distutils, do NOT edit
2COPYING
3MANIFEST
4README
5com.ubuntuone.controlpanel.gui.service.in
6com.ubuntuone.controlpanel.service.in
7pylintrc
8run-tests
9run-tests.bat
10setup.py
11ubuntuone-control-panel-gtk.desktop.in
12ubuntuone-control-panel.in
13ubuntuone.controlpanel.pth
14bin/ubuntuone-control-panel-backend
15bin/ubuntuone-control-panel-gtk
16bin/ubuntuone-control-panel-qt
17data/Ubuntu-R.ttf
18data/computer.png
19data/contacts.png
20data/external_icon_orange.png
21data/external_icon_white.png
22data/facebook.png
23data/files.png
24data/folder.png
25data/music-store.png
26data/music-stream.png
27data/notes.png
28data/overview.png
29data/phone.png
30data/services-bookmarks.png
31data/services-contacts.png
32data/services-files-example.png
33data/services-files.png
34data/sync_status_alert.png
35data/sync_status_disconnected.png
36data/sync_status_sync_done.png
37data/sync_status_syncing.png
38data/twitter.png
39data/u1icon.png
40data/gtk/dashboard.ui
41data/gtk/device.ui
42data/gtk/devices.ui
43data/gtk/install.ui
44data/gtk/management.ui
45data/gtk/overview.ui
46data/gtk/services.ui
47data/gtk/volumes.ui
48data/qt/account.ui
49data/qt/controlpanel.ui
50data/qt/device.ui
51data/qt/devices.ui
52data/qt/filesyncstatus.ui
53data/qt/folders.ui
54data/qt/images.qrc
55data/qt/loadingoverlay.ui
56data/qt/mainwindow.ui
57data/qt/preferences.ui
58data/qt/ubuntuone.qss
59docs/ubuntuone-control-panel-gtk.1
60po/POTFILES.in
61po/ubuntuone-control-panel.pot
62ubuntuone/__init__.py
63ubuntuone/controlpanel/__init__.py
64ubuntuone/controlpanel/backend.py
65ubuntuone/controlpanel/constants.py.in
66ubuntuone/controlpanel/dbus_service.py
67ubuntuone/controlpanel/logger.py
68ubuntuone/controlpanel/login_client.py
69ubuntuone/controlpanel/replication_client.py
70ubuntuone/controlpanel/utils.py
71ubuntuone/controlpanel/dbustests/__init__.py
72ubuntuone/controlpanel/dbustests/test_dbus_service.py
73ubuntuone/controlpanel/dbustests/test_gui_service.py
74ubuntuone/controlpanel/dbustests/test_sd_client/__init__.py
75ubuntuone/controlpanel/dbustests/test_sd_client/test_linux.py
76ubuntuone/controlpanel/gui/__init__.py
77ubuntuone/controlpanel/gui/gtk/__init__.py
78ubuntuone/controlpanel/gui/gtk/gui.py
79ubuntuone/controlpanel/gui/gtk/package_manager.py
80ubuntuone/controlpanel/gui/gtk/widgets.py
81ubuntuone/controlpanel/gui/gtk/tests/__init__.py
82ubuntuone/controlpanel/gui/gtk/tests/test_gui.py
83ubuntuone/controlpanel/gui/gtk/tests/test_gui_basic.py
84ubuntuone/controlpanel/gui/gtk/tests/test_package_manager.py
85ubuntuone/controlpanel/gui/gtk/tests/test_widgets.py
86ubuntuone/controlpanel/gui/qt/__init__.py
87ubuntuone/controlpanel/gui/qt/account.py
88ubuntuone/controlpanel/gui/qt/addfolder.py
89ubuntuone/controlpanel/gui/qt/controlpanel.py
90ubuntuone/controlpanel/gui/qt/device.py
91ubuntuone/controlpanel/gui/qt/devices.py
92ubuntuone/controlpanel/gui/qt/filesyncstatus.py
93ubuntuone/controlpanel/gui/qt/folders.py
94ubuntuone/controlpanel/gui/qt/gotoweb.py
95ubuntuone/controlpanel/gui/qt/gui.py
96ubuntuone/controlpanel/gui/qt/loadingoverlay.py
97ubuntuone/controlpanel/gui/qt/preferences.py
98ubuntuone/controlpanel/gui/qt/ubuntuonebin.py
99ubuntuone/controlpanel/gui/qt/main/__init__.py
100ubuntuone/controlpanel/gui/qt/main/linux.py
101ubuntuone/controlpanel/gui/qt/main/windows.py
102ubuntuone/controlpanel/gui/qt/tests/__init__.py
103ubuntuone/controlpanel/gui/qt/tests/test_account.py
104ubuntuone/controlpanel/gui/qt/tests/test_addfolder.py
105ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py
106ubuntuone/controlpanel/gui/qt/tests/test_device.py
107ubuntuone/controlpanel/gui/qt/tests/test_devices.py
108ubuntuone/controlpanel/gui/qt/tests/test_filesyncstatus.py
109ubuntuone/controlpanel/gui/qt/tests/test_folders.py
110ubuntuone/controlpanel/gui/qt/tests/test_gotoweb.py
111ubuntuone/controlpanel/gui/qt/tests/test_gui.py
112ubuntuone/controlpanel/gui/qt/tests/test_loadingoverlay.py
113ubuntuone/controlpanel/gui/qt/tests/test_preferences.py
114ubuntuone/controlpanel/gui/qt/tests/test_ubuntuonebin.py
115ubuntuone/controlpanel/gui/qt/ui/__init__.py
116ubuntuone/controlpanel/gui/qt/ui/account_ui.py
117ubuntuone/controlpanel/gui/qt/ui/controlpanel_ui.py
118ubuntuone/controlpanel/gui/qt/ui/device_ui.py
119ubuntuone/controlpanel/gui/qt/ui/devices_ui.py
120ubuntuone/controlpanel/gui/qt/ui/filesyncstatus_ui.py
121ubuntuone/controlpanel/gui/qt/ui/folders_ui.py
122ubuntuone/controlpanel/gui/qt/ui/images_rc.py
123ubuntuone/controlpanel/gui/qt/ui/loadingoverlay_ui.py
124ubuntuone/controlpanel/gui/qt/ui/mainwindow_ui.py
125ubuntuone/controlpanel/gui/qt/ui/preferences_ui.py
126ubuntuone/controlpanel/gui/tests/__init__.py
127ubuntuone/controlpanel/gui/tests/test_humanize.py
128ubuntuone/controlpanel/gui/tests/test_url_sign.py
129ubuntuone/controlpanel/sd_client/__init__.py
130ubuntuone/controlpanel/sd_client/linux.py
131ubuntuone/controlpanel/tests/__init__.py
132ubuntuone/controlpanel/tests/test_backend.py
133ubuntuone/controlpanel/tests/test_login_client.py
134ubuntuone/controlpanel/tests/test_replication_client.py
135ubuntuone/controlpanel/tests/test_sd_client.py
136ubuntuone/controlpanel/tests/test_utils.py
137ubuntuone/controlpanel/tests/test_web_client.py
138ubuntuone/controlpanel/web_client/__init__.py
139ubuntuone/controlpanel/web_client/libsoup.py
140ubuntuone/controlpanel/web_client/txwebclient.py
1410
=== modified file 'PKG-INFO'
--- PKG-INFO 2011-08-25 19:37:14 +0000
+++ PKG-INFO 2011-09-26 18:38:27 +0000
@@ -1,30 +1,11 @@
1Metadata-Version: 1.11Metadata-Version: 1.1
2Name: ubuntuone-control-panel2Name: ubuntuone-control-panel
3Version: 1.1.33Version: 2.0.0
4Summary: Ubuntu One Control Panel4Summary: Ubuntu One Control Panel
5Home-page: https://launchpad.net/ubuntuone-control-panel5Home-page: https://launchpad.net/ubuntuone-control-panel
6Author: Natalia Bidart6Author: Natalia Bidart
7Author-email: natalia.bidart@canonical.com7Author-email: natalia.bidart@canonical.com
8License: GPL v38License: GPL v3
9Description: Application to manage a Ubuntu One account. Provides a DBus service to query/modify all the Ubuntu One bits.9Description: Application to manage an Ubuntu One account. Provides a DBus service to query/modify all the Ubuntu One bits.
10Platform: UNKNOWN10Platform: UNKNOWN
11Requires: PyQt4
12Requires: apt
13Requires: aptdaemon
14Requires: dbus
15Requires: defer
16Requires: desktopcouch.application.replication_services
17Requires: gi.repository
18Requires: gobject
19Requires: gtk
20Requires: mocker
21Requires: oauth
22Requires: pango
23Requires: simplejson
24Requires: twisted.application
25Requires: twisted.internet
26Requires: twisted.python.failure
27Requires: twisted.trial.unittest
28Requires: twisted.web
29Requires: ubuntu_sso
30Provides: ubuntuone11Provides: ubuntuone
3112
=== modified file 'bin/ubuntuone-control-panel-qt'
--- bin/ubuntuone-control-panel-qt 2011-08-25 19:37:14 +0000
+++ bin/ubuntuone-control-panel-qt 2011-09-26 18:38:27 +0000
@@ -45,10 +45,19 @@
45 result.add_option("-a", "--alert", dest="alert", action="store_true",45 result.add_option("-a", "--alert", dest="alert", action="store_true",
46 default=False, help="Start Ubuntu One "46 default=False, help="Start Ubuntu One "
47 "alerting the user to its presence.")47 "alerting the user to its presence.")
48 result.add_option("--minimized", dest="minimized", action="store_true",
49 default=False, help="Start Ubuntu One "
50 "only in the notification area, with no visible window. "
51 "Implies --with-icon")
52 result.add_option("--with-icon", dest="with_icon", action="store_true",
53 default=False, help="Start Ubuntu One "
54 "with an icon in the notification area.")
48 return result55 return result
4956
5057
51if __name__ == "__main__":58if __name__ == "__main__":
52 parser = parser_options()59 parser = parser_options()
53 (options, args) = parser.parse_args(sys.argv)60 (options, args) = parser.parse_args(sys.argv)
54 main.main(switch_to=options.switch_to, alert=options.alert)61 main.main(switch_to=options.switch_to,
62 alert=options.alert, minimized=options.minimized,
63 with_icon=options.with_icon)
5564
=== added file 'data/Ubuntu-B.ttf'
56Binary files data/Ubuntu-B.ttf 1970-01-01 00:00:00 +0000 and data/Ubuntu-B.ttf 2011-09-26 18:38:27 +0000 differ65Binary files data/Ubuntu-B.ttf 1970-01-01 00:00:00 +0000 and data/Ubuntu-B.ttf 2011-09-26 18:38:27 +0000 differ
=== modified file 'data/gtk/overview.ui'
--- data/gtk/overview.ui 2011-07-22 21:26:48 +0000
+++ data/gtk/overview.ui 2011-09-26 18:38:27 +0000
@@ -150,7 +150,7 @@
150 <property name="can_focus">False</property>150 <property name="can_focus">False</property>
151 <property name="xalign">0</property>151 <property name="xalign">0</property>
152 <property name="label" translatable="yes">Stay Productive152 <property name="label" translatable="yes">Stay Productive
153&lt;span foreground="#909090"&gt;Keep your Firefox bookmarks and Tomboy notes synced&lt;/span&gt;</property>153&lt;span foreground="#909090"&gt;Keep your Tomboy notes synced&lt;/span&gt;</property>
154 <property name="use_markup">True</property>154 <property name="use_markup">True</property>
155 <property name="wrap">True</property>155 <property name="wrap">True</property>
156 </object>156 </object>
@@ -251,36 +251,11 @@
251 <property name="use_action_appearance">False</property>251 <property name="use_action_appearance">False</property>
252 <signal name="clicked" handler="on_join_now_button_clicked" swapped="no"/>252 <signal name="clicked" handler="on_join_now_button_clicked" swapped="no"/>
253 <child>253 <child>
254 <object class="GtkVBox" id="vbox4">254 <object class="GtkLabel" id="label1">
255 <property name="visible">True</property>255 <property name="visible">True</property>
256 <property name="can_focus">False</property>256 <property name="can_focus">False</property>
257 <property name="spacing">5</property>257 <property name="label" translatable="yes">&lt;span font_size="xx-large" foreground="#4d4d4d"&gt;Join now&lt;/span&gt;</property>
258 <child>258 <property name="use_markup">True</property>
259 <object class="GtkLabel" id="label1">
260 <property name="visible">True</property>
261 <property name="can_focus">False</property>
262 <property name="label" translatable="yes">&lt;span font_size="xx-large" foreground="#4d4d4d"&gt;Join now&lt;/span&gt;</property>
263 <property name="use_markup">True</property>
264 </object>
265 <packing>
266 <property name="expand">True</property>
267 <property name="fill">True</property>
268 <property name="position">0</property>
269 </packing>
270 </child>
271 <child>
272 <object class="GtkLabel" id="label2">
273 <property name="visible">True</property>
274 <property name="can_focus">False</property>
275 <property name="label" translatable="yes">&lt;span foreground="#909090"&gt;2GB of free storage&lt;/span&gt;</property>
276 <property name="use_markup">True</property>
277 </object>
278 <packing>
279 <property name="expand">True</property>
280 <property name="fill">True</property>
281 <property name="position">1</property>
282 </packing>
283 </child>
284 </object>259 </object>
285 </child>260 </child>
286 </object>261 </object>
287262
=== modified file 'data/gtk/services.ui'
--- data/gtk/services.ui 2011-07-22 21:26:48 +0000
+++ data/gtk/services.ui 2011-09-26 18:38:27 +0000
@@ -59,16 +59,21 @@
59 <property name="use_action_appearance">False</property>59 <property name="use_action_appearance">False</property>
60 <property name="draw_indicator">True</property>60 <property name="draw_indicator">True</property>
61 </object>61 </object>
62 <packing>
63 <property name="x_options"></property>
64 <property name="y_options"></property>
65 </packing>
62 </child>66 </child>
63 <child>67 <child>
64 <object class="GtkImage" id="files_icon">68 <object class="GtkImage" id="files_icon">
65 <property name="visible">True</property>69 <property name="visible">True</property>
66 <property name="can_focus">False</property>70 <property name="can_focus">False</property>
67 <property name="xpad">5</property>
68 </object>71 </object>
69 <packing>72 <packing>
70 <property name="left_attach">1</property>73 <property name="left_attach">1</property>
71 <property name="right_attach">2</property>74 <property name="right_attach">2</property>
75 <property name="x_options"></property>
76 <property name="y_options"></property>
72 </packing>77 </packing>
73 </child>78 </child>
74 <child>79 <child>
@@ -154,8 +159,6 @@
154 <object class="GtkImage" id="files_example">159 <object class="GtkImage" id="files_example">
155 <property name="visible">True</property>160 <property name="visible">True</property>
156 <property name="can_focus">False</property>161 <property name="can_focus">False</property>
157 <property name="xpad">5</property>
158 <property name="ypad">5</property>
159 </object>162 </object>
160 <packing>163 <packing>
161 <property name="expand">False</property>164 <property name="expand">False</property>
@@ -188,6 +191,7 @@
188 <object class="GtkAlignment" id="alignment3">191 <object class="GtkAlignment" id="alignment3">
189 <property name="visible">True</property>192 <property name="visible">True</property>
190 <property name="can_focus">False</property>193 <property name="can_focus">False</property>
194 <property name="top_padding">6</property>
191 <child>195 <child>
192 <object class="GtkHBox" id="hbox3">196 <object class="GtkHBox" id="hbox3">
193 <property name="visible">True</property>197 <property name="visible">True</property>
@@ -203,6 +207,7 @@
203 <property name="can_focus">False</property>207 <property name="can_focus">False</property>
204 <property name="n_rows">2</property>208 <property name="n_rows">2</property>
205 <property name="n_columns">3</property>209 <property name="n_columns">3</property>
210 <property name="column_spacing">5</property>
206 <property name="row_spacing">5</property>211 <property name="row_spacing">5</property>
207 <child>212 <child>
208 <object class="GtkCheckButton" id="contacts_check">213 <object class="GtkCheckButton" id="contacts_check">
@@ -212,16 +217,21 @@
212 <property name="use_action_appearance">False</property>217 <property name="use_action_appearance">False</property>
213 <property name="draw_indicator">True</property>218 <property name="draw_indicator">True</property>
214 </object>219 </object>
220 <packing>
221 <property name="x_options"></property>
222 <property name="y_options"></property>
223 </packing>
215 </child>224 </child>
216 <child>225 <child>
217 <object class="GtkImage" id="contacts_icon">226 <object class="GtkImage" id="contacts_icon">
218 <property name="visible">True</property>227 <property name="visible">True</property>
219 <property name="can_focus">False</property>228 <property name="can_focus">False</property>
220 <property name="xpad">5</property>
221 </object>229 </object>
222 <packing>230 <packing>
223 <property name="left_attach">1</property>231 <property name="left_attach">1</property>
224 <property name="right_attach">2</property>232 <property name="right_attach">2</property>
233 <property name="x_options"></property>
234 <property name="y_options"></property>
225 </packing>235 </packing>
226 </child>236 </child>
227 <child>237 <child>
@@ -245,7 +255,6 @@
245 <property name="label" translatable="yes">&lt;span font_size="small"&gt;Once enabled, visit the &lt;a href="https://one.ubuntu.com"&gt;Ubuntu One website&lt;/a&gt; to manage your contacts, including Gmail and Facebook import&lt;/span&gt;</property>255 <property name="label" translatable="yes">&lt;span font_size="small"&gt;Once enabled, visit the &lt;a href="https://one.ubuntu.com"&gt;Ubuntu One website&lt;/a&gt; to manage your contacts, including Gmail and Facebook import&lt;/span&gt;</property>
246 <property name="use_markup">True</property>256 <property name="use_markup">True</property>
247 <property name="wrap">True</property>257 <property name="wrap">True</property>
248 <property name="width_chars">35</property>
249 </object>258 </object>
250 <packing>259 <packing>
251 <property name="left_attach">2</property>260 <property name="left_attach">2</property>
@@ -269,92 +278,13 @@
269 </child>278 </child>
270 </object>279 </object>
271 <packing>280 <packing>
272 <property name="expand">False</property>281 <property name="expand">True</property>
273 <property name="fill">True</property>282 <property name="fill">True</property>
274 <property name="position">0</property>283 <property name="position">0</property>
275 </packing>284 </packing>
276 </child>285 </child>
277 <child>286 <child>
278 <object class="GtkVBox" id="bookmarks">287 <placeholder/>
279 <property name="visible">True</property>
280 <property name="can_focus">False</property>
281 <child>
282 <object class="GtkTable" id="bookmarks_sync">
283 <property name="visible">True</property>
284 <property name="can_focus">False</property>
285 <property name="n_rows">2</property>
286 <property name="n_columns">3</property>
287 <property name="row_spacing">5</property>
288 <child>
289 <object class="GtkCheckButton" id="bookmarks_check">
290 <property name="visible">True</property>
291 <property name="can_focus">True</property>
292 <property name="receives_default">False</property>
293 <property name="use_action_appearance">False</property>
294 <property name="draw_indicator">True</property>
295 </object>
296 </child>
297 <child>
298 <object class="GtkImage" id="bookmarks_icon">
299 <property name="visible">True</property>
300 <property name="can_focus">False</property>
301 <property name="xpad">5</property>
302 </object>
303 <packing>
304 <property name="left_attach">1</property>
305 <property name="right_attach">2</property>
306 </packing>
307 </child>
308 <child>
309 <object class="GtkLabel" id="label6">
310 <property name="visible">True</property>
311 <property name="can_focus">False</property>
312 <property name="xalign">0</property>
313 <property name="label" translatable="yes">Enable Bookmarks Sync</property>
314 </object>
315 <packing>
316 <property name="left_attach">2</property>
317 <property name="right_attach">3</property>
318 </packing>
319 </child>
320 <child>
321 <object class="GtkLabel" id="label7">
322 <property name="visible">True</property>
323 <property name="can_focus">False</property>
324 <property name="xalign">0</property>
325 <property name="yalign">0</property>
326 <property name="label" translatable="yes">&lt;span font_size="small"&gt;Bookmarks sync works with Firefox&lt;/span&gt;</property>
327 <property name="use_markup">True</property>
328 <property name="wrap">True</property>
329 <property name="width_chars">30</property>
330 </object>
331 <packing>
332 <property name="left_attach">2</property>
333 <property name="right_attach">3</property>
334 <property name="top_attach">1</property>
335 <property name="bottom_attach">2</property>
336 </packing>
337 </child>
338 <child>
339 <placeholder/>
340 </child>
341 <child>
342 <placeholder/>
343 </child>
344 </object>
345 <packing>
346 <property name="expand">False</property>
347 <property name="fill">True</property>
348 <property name="position">0</property>
349 </packing>
350 </child>
351 </object>
352 <packing>
353 <property name="expand">False</property>
354 <property name="fill">True</property>
355 <property name="pack_type">end</property>
356 <property name="position">1</property>
357 </packing>
358 </child>288 </child>
359 </object>289 </object>
360 </child>290 </child>
361291
=== modified file 'data/qt/account.ui'
--- data/qt/account.ui 2011-08-25 19:37:14 +0000
+++ data/qt/account.ui 2011-09-26 18:38:27 +0000
@@ -35,7 +35,16 @@
35 <string>Your services</string>35 <string>Your services</string>
36 </property>36 </property>
37 <layout class="QVBoxLayout" name="verticalLayout_3">37 <layout class="QVBoxLayout" name="verticalLayout_3">
38 <property name="margin">38 <property name="leftMargin">
39 <number>10</number>
40 </property>
41 <property name="topMargin">
42 <number>0</number>
43 </property>
44 <property name="rightMargin">
45 <number>0</number>
46 </property>
47 <property name="bottomMargin">
39 <number>0</number>48 <number>0</number>
40 </property>49 </property>
41 <item>50 <item>
@@ -61,11 +70,23 @@
61 <string>Personal details</string>70 <string>Personal details</string>
62 </property>71 </property>
63 <layout class="QVBoxLayout" name="verticalLayout_4">72 <layout class="QVBoxLayout" name="verticalLayout_4">
64 <property name="margin">73 <property name="leftMargin">
74 <number>10</number>
75 </property>
76 <property name="topMargin">
77 <number>0</number>
78 </property>
79 <property name="rightMargin">
80 <number>0</number>
81 </property>
82 <property name="bottomMargin">
65 <number>0</number>83 <number>0</number>
66 </property>84 </property>
67 <item>85 <item>
68 <layout class="QVBoxLayout" name="verticalLayout_2">86 <layout class="QVBoxLayout" name="verticalLayout_2">
87 <property name="leftMargin">
88 <number>6</number>
89 </property>
69 <item>90 <item>
70 <widget class="QLabel" name="name_label">91 <widget class="QLabel" name="name_label">
71 <property name="text">92 <property name="text">
7293
=== modified file 'data/qt/controlpanel.ui'
--- data/qt/controlpanel.ui 2011-08-25 19:37:14 +0000
+++ data/qt/controlpanel.ui 2011-09-26 18:38:27 +0000
@@ -6,8 +6,8 @@
6 <rect>6 <rect>
7 <x>0</x>7 <x>0</x>
8 <y>0</y>8 <y>0</y>
9 <width>367</width>9 <width>387</width>
10 <height>142</height>10 <height>168</height>
11 </rect>11 </rect>
12 </property>12 </property>
13 <property name="sizePolicy">13 <property name="sizePolicy">
@@ -20,215 +20,247 @@
20 <string notr="true">Form</string>20 <string notr="true">Form</string>
21 </property>21 </property>
22 <layout class="QVBoxLayout" name="verticalLayout">22 <layout class="QVBoxLayout" name="verticalLayout">
23 <property name="spacing">
24 <number>3</number>
25 </property>
26 <property name="margin">23 <property name="margin">
27 <number>0</number>24 <number>0</number>
28 </property>25 </property>
29 <item>26 <item>
30 <widget class="QFrame" name="frame_header">27 <widget class="QStackedWidget" name="switcher">
31 <layout class="QHBoxLayout" name="horizontalLayout_2">28 <property name="currentIndex">
32 <property name="spacing">29 <number>1</number>
33 <number>5</number>30 </property>
34 </property>31 <widget class="QWidget" name="management">
35 <property name="margin">32 <property name="sizePolicy">
36 <number>0</number>33 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
37 </property>34 <horstretch>0</horstretch>
38 <item>35 <verstretch>0</verstretch>
39 <widget class="QFrame" name="frame_greeting">36 </sizepolicy>
40 <layout class="QVBoxLayout" name="verticalLayout_4">37 </property>
41 <property name="margin">38 <layout class="QVBoxLayout" name="verticalLayout_5">
42 <number>0</number>39 <property name="margin">
43 </property>40 <number>0</number>
44 <item>41 </property>
45 <widget class="QLabel" name="greeting_label">42 <item>
46 <property name="alignment">43 <layout class="QVBoxLayout" name="verticalLayout_2">
47 <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>44 <item>
48 </property>45 <widget class="QFrame" name="frame_header">
49 </widget>46 <layout class="QHBoxLayout" name="horizontalLayout_2">
50 </item>
51 </layout>
52 </widget>
53 </item>
54 <item>
55 <spacer name="horizontalSpacer">
56 <property name="orientation">
57 <enum>Qt::Horizontal</enum>
58 </property>
59 <property name="sizeType">
60 <enum>QSizePolicy::Fixed</enum>
61 </property>
62 <property name="sizeHint" stdset="0">
63 <size>
64 <width>15</width>
65 <height>20</height>
66 </size>
67 </property>
68 </spacer>
69 </item>
70 <item>
71 <widget class="QFrame" name="frame_storage">
72 <property name="sizePolicy">
73 <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
74 <horstretch>0</horstretch>
75 <verstretch>0</verstretch>
76 </sizepolicy>
77 </property>
78 <property name="minimumSize">
79 <size>
80 <width>165</width>
81 <height>0</height>
82 </size>
83 </property>
84 <property name="maximumSize">
85 <size>
86 <width>165</width>
87 <height>16777215</height>
88 </size>
89 </property>
90 <layout class="QVBoxLayout" name="vLayoutStorage">
91 <property name="spacing">
92 <number>6</number>
93 </property>
94 <property name="sizeConstraint">
95 <enum>QLayout::SetDefaultConstraint</enum>
96 </property>
97 <property name="margin">
98 <number>0</number>
99 </property>
100 <item>
101 <widget class="QFrame" name="frame_quota">
102 <layout class="QVBoxLayout" name="verticalLayout_3">
103 <property name="spacing">47 <property name="spacing">
104 <number>2</number>48 <number>5</number>
105 </property>49 </property>
106 <property name="margin">50 <property name="margin">
107 <number>0</number>51 <number>0</number>
108 </property>52 </property>
109 <item>53 <item>
110 <widget class="QLabel" name="percentage_usage_label">54 <widget class="QFrame" name="frame_greeting">
111 <property name="sizePolicy">55 <layout class="QVBoxLayout" name="verticalLayout_4">
112 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">56 <property name="margin">
113 <horstretch>0</horstretch>57 <number>0</number>
114 <verstretch>0</verstretch>58 </property>
115 </sizepolicy>59 <item>
116 </property>60 <widget class="QLabel" name="greeting_label">
117 <property name="text">61 <property name="alignment">
118 <string notr="true"/>62 <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
119 </property>63 </property>
120 </widget>64 </widget>
121 </item>65 </item>
122 <item>66 </layout>
123 <widget class="QLabel" name="quota_usage_label">67 </widget>
124 <property name="font">68 </item>
125 <font>69 <item>
126 <pointsize>8</pointsize>70 <spacer name="horizontalSpacer">
127 </font>71 <property name="orientation">
128 </property>72 <enum>Qt::Horizontal</enum>
129 <property name="text">73 </property>
130 <string/>74 <property name="sizeType">
131 </property>75 <enum>QSizePolicy::Fixed</enum>
76 </property>
77 <property name="sizeHint" stdset="0">
78 <size>
79 <width>15</width>
80 <height>20</height>
81 </size>
82 </property>
83 </spacer>
84 </item>
85 <item>
86 <widget class="QFrame" name="frame_storage">
87 <property name="sizePolicy">
88 <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
89 <horstretch>0</horstretch>
90 <verstretch>0</verstretch>
91 </sizepolicy>
92 </property>
93 <property name="minimumSize">
94 <size>
95 <width>165</width>
96 <height>0</height>
97 </size>
98 </property>
99 <property name="maximumSize">
100 <size>
101 <width>165</width>
102 <height>16777215</height>
103 </size>
104 </property>
105 <layout class="QVBoxLayout" name="vLayoutStorage">
106 <property name="spacing">
107 <number>6</number>
108 </property>
109 <property name="sizeConstraint">
110 <enum>QLayout::SetFixedSize</enum>
111 </property>
112 <property name="margin">
113 <number>0</number>
114 </property>
115 <item>
116 <widget class="QFrame" name="frame_quota">
117 <layout class="QVBoxLayout" name="verticalLayout_3">
118 <property name="spacing">
119 <number>2</number>
120 </property>
121 <property name="margin">
122 <number>0</number>
123 </property>
124 <item>
125 <widget class="QLabel" name="percentage_usage_label">
126 <property name="sizePolicy">
127 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
128 <horstretch>0</horstretch>
129 <verstretch>0</verstretch>
130 </sizepolicy>
131 </property>
132 <property name="text">
133 <string notr="true"/>
134 </property>
135 <property name="OverQuota" stdset="0">
136 <bool>false</bool>
137 </property>
138 </widget>
139 </item>
140 <item>
141 <widget class="QLabel" name="quota_usage_label">
142 <property name="font">
143 <font>
144 <pointsize>8</pointsize>
145 </font>
146 </property>
147 <property name="text">
148 <string/>
149 </property>
150 <property name="OverQuota" stdset="0">
151 <bool>false</bool>
152 </property>
153 </widget>
154 </item>
155 </layout>
156 <zorder>quota_usage_label</zorder>
157 <zorder>percentage_usage_label</zorder>
158 </widget>
159 </item>
160 <item>
161 <widget class="GoToWebButton" name="get_more_space_button">
162 <property name="text">
163 <string>Get more storage</string>
164 </property>
165 </widget>
166 </item>
167 </layout>
168 </widget>
169 </item>
170 <item>
171 <widget class="QFrame" name="frame_status">
172 <property name="sizePolicy">
173 <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
174 <horstretch>0</horstretch>
175 <verstretch>0</verstretch>
176 </sizepolicy>
177 </property>
178 <property name="minimumSize">
179 <size>
180 <width>165</width>
181 <height>0</height>
182 </size>
183 </property>
184 <property name="maximumSize">
185 <size>
186 <width>165</width>
187 <height>16777215</height>
188 </size>
189 </property>
190 <layout class="QHBoxLayout" name="horizontalLayout_8">
191 <property name="sizeConstraint">
192 <enum>QLayout::SetMinimumSize</enum>
193 </property>
194 <property name="margin">
195 <number>0</number>
196 </property>
197 <item>
198 <widget class="FileSyncStatus" name="file_sync_status" native="true">
199 <property name="sizePolicy">
200 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
201 <horstretch>0</horstretch>
202 <verstretch>0</verstretch>
203 </sizepolicy>
204 </property>
205 <property name="minimumSize">
206 <size>
207 <width>0</width>
208 <height>0</height>
209 </size>
210 </property>
211 <property name="maximumSize">
212 <size>
213 <width>165</width>
214 <height>16777215</height>
215 </size>
216 </property>
217 </widget>
218 </item>
219 </layout>
132 </widget>220 </widget>
133 </item>221 </item>
134 </layout>222 </layout>
135 <zorder>quota_usage_label</zorder>223 </widget>
136 <zorder>percentage_usage_label</zorder>224 </item>
137 </widget>225 <item>
138 </item>226 <widget class="QTabWidget" name="tab_widget">
139 <item>
140 <widget class="GoToWebButton" name="get_more_space_button">
141 <property name="text">
142 <string>Get more storage</string>
143 </property>
144 </widget>
145 </item>
146 </layout>
147 </widget>
148 </item>
149 <item>
150 <widget class="QFrame" name="frame_status">
151 <property name="sizePolicy">
152 <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
153 <horstretch>0</horstretch>
154 <verstretch>0</verstretch>
155 </sizepolicy>
156 </property>
157 <property name="minimumSize">
158 <size>
159 <width>165</width>
160 <height>0</height>
161 </size>
162 </property>
163 <property name="maximumSize">
164 <size>
165 <width>165</width>
166 <height>16777215</height>
167 </size>
168 </property>
169 <layout class="QHBoxLayout" name="horizontalLayout_8">
170 <property name="margin">
171 <number>0</number>
172 </property>
173 <item>
174 <widget class="FileSyncStatus" name="file_sync_status" native="true">
175 <property name="sizePolicy">227 <property name="sizePolicy">
176 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">228 <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
177 <horstretch>0</horstretch>229 <horstretch>0</horstretch>
178 <verstretch>0</verstretch>230 <verstretch>0</verstretch>
179 </sizepolicy>231 </sizepolicy>
180 </property>232 </property>
181 <property name="minimumSize">233 <property name="currentIndex">
182 <size>234 <number>0</number>
183 <width>0</width>235 </property>
184 <height>0</height>236 <widget class="FoldersPanel" name="folders_tab">
185 </size>237 <attribute name="title">
186 </property>238 <string>Folders</string>
187 <property name="maximumSize">239 </attribute>
188 <size>240 </widget>
189 <width>165</width>241 <widget class="DevicesPanel" name="devices_tab">
190 <height>16777215</height>242 <attribute name="title">
191 </size>243 <string>Devices</string>
192 </property>244 </attribute>
245 </widget>
246 <widget class="PreferencesPanel" name="preferences_tab">
247 <attribute name="title">
248 <string>Settings</string>
249 </attribute>
250 </widget>
251 <widget class="AccountPanel" name="account_tab">
252 <attribute name="title">
253 <string>Account information</string>
254 </attribute>
255 </widget>
193 </widget>256 </widget>
194 </item>257 </item>
195 </layout>258 </layout>
196 </widget>259 </item>
197 </item>260 </layout>
198 </layout>261 </widget>
199 </widget>262 <widget class="QWidget" name="empty"/>
200 </item>263 <widget class="SignInPanel" name="signin"/>
201 <item>
202 <widget class="QTabWidget" name="tab_widget">
203 <property name="sizePolicy">
204 <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
205 <horstretch>0</horstretch>
206 <verstretch>0</verstretch>
207 </sizepolicy>
208 </property>
209 <property name="currentIndex">
210 <number>0</number>
211 </property>
212 <widget class="FoldersPanel" name="folders_tab">
213 <attribute name="title">
214 <string>Folders</string>
215 </attribute>
216 </widget>
217 <widget class="DevicesPanel" name="devices_tab">
218 <attribute name="title">
219 <string>Devices</string>
220 </attribute>
221 </widget>
222 <widget class="PreferencesPanel" name="preferences_tab">
223 <attribute name="title">
224 <string>Settings</string>
225 </attribute>
226 </widget>
227 <widget class="AccountPanel" name="account_tab">
228 <attribute name="title">
229 <string>Account information</string>
230 </attribute>
231 </widget>
232 </widget>264 </widget>
233 </item>265 </item>
234 <item>266 <item>
@@ -371,9 +403,14 @@
371 <header>ubuntuone.controlpanel.gui.qt.account</header>403 <header>ubuntuone.controlpanel.gui.qt.account</header>
372 <container>1</container>404 <container>1</container>
373 </customwidget>405 </customwidget>
406 <customwidget>
407 <class>SignInPanel</class>
408 <extends>QWidget</extends>
409 <header>ubuntuone.controlpanel.gui.qt.signin</header>
410 <container>1</container>
411 </customwidget>
374 </customwidgets>412 </customwidgets>
375 <tabstops>413 <tabstops>
376 <tabstop>tab_widget</tabstop>
377 <tabstop>help_button</tabstop>414 <tabstop>help_button</tabstop>
378 <tabstop>twitter_button</tabstop>415 <tabstop>twitter_button</tabstop>
379 <tabstop>facebook_button</tabstop>416 <tabstop>facebook_button</tabstop>
380417
=== modified file 'data/qt/images.qrc'
--- data/qt/images.qrc 2011-08-25 19:37:14 +0000
+++ data/qt/images.qrc 2011-09-26 18:38:27 +0000
@@ -15,6 +15,7 @@
15 <file>../facebook.png</file>15 <file>../facebook.png</file>
16 <file>../external_icon_white.png</file>16 <file>../external_icon_white.png</file>
17 <file>../Ubuntu-R.ttf</file>17 <file>../Ubuntu-R.ttf</file>
18 <file>../Ubuntu-B.ttf</file>
18 <file>ubuntuone.qss</file>19 <file>ubuntuone.qss</file>
19 </qresource>20 </qresource>
20</RCC>21</RCC>
2122
=== modified file 'data/qt/preferences.ui'
--- data/qt/preferences.ui 2011-08-25 19:37:14 +0000
+++ data/qt/preferences.ui 2011-09-26 18:38:27 +0000
@@ -6,7 +6,7 @@
6 <rect>6 <rect>
7 <x>0</x>7 <x>0</x>
8 <y>0</y>8 <y>0</y>
9 <width>433</width>9 <width>512</width>
10 <height>328</height>10 <height>328</height>
11 </rect>11 </rect>
12 </property>12 </property>
@@ -138,14 +138,14 @@
138 <item>138 <item>
139 <widget class="QCheckBox" name="udf_autosubscribe_checkbox">139 <widget class="QCheckBox" name="udf_autosubscribe_checkbox">
140 <property name="text">140 <property name="text">
141 <string>Automatically sync all selected folders on this computer to the cloud</string>141 <string>Automatically sync all new cloud folders to this computer</string>
142 </property>142 </property>
143 </widget>143 </widget>
144 </item>144 </item>
145 <item>145 <item>
146 <widget class="QCheckBox" name="share_autosubscribe_checkbox">146 <widget class="QCheckBox" name="share_autosubscribe_checkbox">
147 <property name="text">147 <property name="text">
148 <string>Automatically sync all folders shared with me by other to this computer</string>148 <string>Automatically sync all folders shared with me to this computer</string>
149 </property>149 </property>
150 </widget>150 </widget>
151 </item>151 </item>
152152
=== added file 'data/qt/signin.ui'
--- data/qt/signin.ui 1970-01-01 00:00:00 +0000
+++ data/qt/signin.ui 2011-09-26 18:38:27 +0000
@@ -0,0 +1,203 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>Form</class>
4 <widget class="QWidget" name="Form">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>344</width>
10 <height>312</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Form</string>
15 </property>
16 <layout class="QHBoxLayout" name="horizontalLayout_3">
17 <property name="margin">
18 <number>0</number>
19 </property>
20 <item>
21 <widget class="QFrame" name="signin">
22 <layout class="QVBoxLayout" name="sign_in">
23 <property name="spacing">
24 <number>15</number>
25 </property>
26 <property name="margin">
27 <number>3</number>
28 </property>
29 <item>
30 <widget class="QLabel" name="sign_in_label">
31 <property name="text">
32 <string>Sign in to Ubuntu One</string>
33 </property>
34 </widget>
35 </item>
36 <item>
37 <widget class="QLabel" name="description_label">
38 <property name="text">
39 <string>Sign in with yur existing Ubuntu One username and password.</string>
40 </property>
41 </widget>
42 </item>
43 <item>
44 <layout class="QHBoxLayout" name="horizontalLayout">
45 <item>
46 <layout class="QVBoxLayout" name="verticalLayout_2">
47 <property name="spacing">
48 <number>15</number>
49 </property>
50 <item>
51 <layout class="QVBoxLayout" name="verticalLayout_4">
52 <property name="spacing">
53 <number>0</number>
54 </property>
55 <item>
56 <widget class="QLabel" name="email_label">
57 <property name="text">
58 <string>Email address</string>
59 </property>
60 </widget>
61 </item>
62 <item>
63 <widget class="QLineEdit" name="email_entry">
64 <property name="text">
65 <string/>
66 </property>
67 </widget>
68 </item>
69 </layout>
70 </item>
71 <item>
72 <layout class="QVBoxLayout" name="verticalLayout_3">
73 <property name="spacing">
74 <number>0</number>
75 </property>
76 <item>
77 <widget class="QLabel" name="password_label">
78 <property name="text">
79 <string>Password</string>
80 </property>
81 </widget>
82 </item>
83 <item>
84 <widget class="QLineEdit" name="password_entry">
85 <property name="echoMode">
86 <enum>QLineEdit::Password</enum>
87 </property>
88 </widget>
89 </item>
90 </layout>
91 </item>
92 <item>
93 <layout class="QHBoxLayout" name="horizontalLayout_2">
94 <item>
95 <widget class="QPushButton" name="signin_button">
96 <property name="text">
97 <string>Sign in</string>
98 </property>
99 <property name="default">
100 <bool>true</bool>
101 </property>
102 </widget>
103 </item>
104 <item>
105 <widget class="QPushButton" name="cancel_button">
106 <property name="text">
107 <string>Cancel</string>
108 </property>
109 <property name="secondary" stdset="0">
110 <bool>true</bool>
111 </property>
112 </widget>
113 </item>
114 <item>
115 <spacer name="horizontalSpacer">
116 <property name="orientation">
117 <enum>Qt::Horizontal</enum>
118 </property>
119 <property name="sizeHint" stdset="0">
120 <size>
121 <width>40</width>
122 <height>20</height>
123 </size>
124 </property>
125 </spacer>
126 </item>
127 </layout>
128 </item>
129 <item>
130 <layout class="QHBoxLayout" name="horizontalLayout_4">
131 <item>
132 <widget class="GoToWebButton" name="forgot_password_button">
133 <property name="sizePolicy">
134 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
135 <horstretch>0</horstretch>
136 <verstretch>0</verstretch>
137 </sizepolicy>
138 </property>
139 <property name="text">
140 <string>Forgot your password?</string>
141 </property>
142 </widget>
143 </item>
144 <item>
145 <spacer name="horizontalSpacer_3">
146 <property name="orientation">
147 <enum>Qt::Horizontal</enum>
148 </property>
149 <property name="sizeHint" stdset="0">
150 <size>
151 <width>40</width>
152 <height>20</height>
153 </size>
154 </property>
155 </spacer>
156 </item>
157 </layout>
158 </item>
159 </layout>
160 </item>
161 <item>
162 <spacer name="horizontalSpacer_2">
163 <property name="orientation">
164 <enum>Qt::Horizontal</enum>
165 </property>
166 <property name="sizeHint" stdset="0">
167 <size>
168 <width>40</width>
169 <height>20</height>
170 </size>
171 </property>
172 </spacer>
173 </item>
174 </layout>
175 </item>
176 <item>
177 <spacer name="verticalSpacer">
178 <property name="orientation">
179 <enum>Qt::Vertical</enum>
180 </property>
181 <property name="sizeHint" stdset="0">
182 <size>
183 <width>20</width>
184 <height>40</height>
185 </size>
186 </property>
187 </spacer>
188 </item>
189 </layout>
190 </widget>
191 </item>
192 </layout>
193 </widget>
194 <customwidgets>
195 <customwidget>
196 <class>GoToWebButton</class>
197 <extends>QPushButton</extends>
198 <header>ubuntuone.controlpanel.gui.qt.gotoweb</header>
199 </customwidget>
200 </customwidgets>
201 <resources/>
202 <connections/>
203</ui>
0204
=== modified file 'data/qt/ubuntuone.qss'
--- data/qt/ubuntuone.qss 2011-08-25 19:37:14 +0000
+++ data/qt/ubuntuone.qss 2011-09-26 18:38:27 +0000
@@ -1,5 +1,5 @@
1QMainWindow {1QMainWindow {
2 background-color: #dd4814;2 background-color: #aea79f;
3}3}
44
5QWidget {5QWidget {
@@ -12,6 +12,7 @@
12 border: none;12 border: none;
13}13}
1414
15QFrame#signin,
15QFrame#frame_header {16QFrame#frame_header {
16 background: #ffffff;17 background: #ffffff;
17 border-radius: 5px;18 border-radius: 5px;
@@ -137,6 +138,7 @@
137 border: none;138 border: none;
138}139}
139140
141GoToWebButton#forgot_password_button,
140GoToWebButton#share_publish_button {142GoToWebButton#share_publish_button {
141 background: transparent;143 background: transparent;
142 border: none;144 border: none;
@@ -216,11 +218,8 @@
216 padding-top: 30px;218 padding-top: 30px;
217 border: none;219 border: none;
218 margin-top: 1ex;220 margin-top: 1ex;
219}
220
221QGroupBox::title {
222 color: #333333;221 color: #333333;
223 font: bold 15px;222 font: bold 14px;
224}223}
225224
226QGroupBox#profile,225QGroupBox#profile,
@@ -228,6 +227,11 @@
228 padding-left: 5px;227 padding-left: 5px;
229}228}
230229
230QGroupBox#bandwidth_settings,
231QGroupBox#file_sync_settings {
232 padding-left: 20px;
233}
234
231QListWidget {235QListWidget {
232 background: #f7f6f5;236 background: #f7f6f5;
233 alternate-background-color: #efedec;237 alternate-background-color: #efedec;
@@ -237,6 +241,10 @@
237 min-height: 48px;241 min-height: 48px;
238}242}
239243
244QLabel[OverQuota="false"] {
245 color: #333333;
246}
247
240QLabel#other_devices_label {248QLabel#other_devices_label {
241 font: bold 16px;249 font: bold 16px;
242}250}
@@ -249,6 +257,20 @@
249 color: white;257 color: white;
250}258}
251259
260QLabel#sign_in_label {
261 font: 16px;
262}
263
264QLabel#email_label,
265QLabel#password_label {
266 font-size: 10px;
267}
268
269QLabel[OverQuota="true"],
270QLabel#warning_label {
271 color: #df2d1f;
272}
273
252QAbstractItemView {274QAbstractItemView {
253 border-style: solid;275 border-style: solid;
254 border-color: #898989;276 border-color: #898989;
255277
=== modified file 'debian/changelog'
--- debian/changelog 2011-09-07 13:35:18 +0000
+++ debian/changelog 2011-09-26 18:38:27 +0000
@@ -1,3 +1,32 @@
1ubuntuone-control-panel (2.0.0-0ubuntu1) UNRELEASED; urgency=low
2
3 * New upstream release:
4
5 [ Alejandro J. Cura <alecu@canonical.com>]
6 - Do not throw a webclient error when closing
7 (LP: #845105).
8 [ Natalia B. Bidart <natalia.bidart@canonical.com> ]
9 - Removed all code related to Bookmarks (LP: #850142).
10 - Replaces references to "Evolution" by "Thunderbird" (LP: #849494).
11 [ Rodney Dawes <rodney.dawes@canonical.com> ]
12 - Don't install a .desktop file for control panel
13 (part of LP: #838778).
14 - Point the indicator/Unity API at the installer .desktop file
15 (part of LP: #838778).
16 - Set the WMCLASS so Unity will fall back properly
17 (part of LP: #838778).
18 - Fix a few grammar mistakes (LP: #835093).
19 - Don't show the "Get NGB free!" label on "Join now" button at all
20 (LP: #819955).
21
22 * debian/control:
23 - ubuntuone-control-panel-gtk depends now on ubuntuone-installer >= 2.0.0.
24 - require ubuntuone-client >= 2.0.0.
25 - require ubuntu-sso-client >= 1.4.0.
26 - no longer install a .desktop file (will be installed by ubuntuone-installer).
27
28 -- Natalia Bidart (nessita) <natalia.bidart@canonical.com> Mon, 26 Sep 2011 14:55:15 -0300
29
1ubuntuone-control-panel (1.1.3-0ubuntu2) UNRELEASED; urgency=low30ubuntuone-control-panel (1.1.3-0ubuntu2) UNRELEASED; urgency=low
231
3 [ Paul Stewart ]32 [ Paul Stewart ]
433
=== modified file 'debian/control'
--- debian/control 2011-08-26 21:22:36 +0000
+++ debian/control 2011-09-26 18:38:27 +0000
@@ -17,7 +17,7 @@
17 ${python:Depends},17 ${python:Depends},
18 python,18 python,
19 python-ubuntuone-control-panel (= ${binary:Version}),19 python-ubuntuone-control-panel (= ${binary:Version}),
20 ubuntuone-client (>= 1.7.1),20 ubuntuone-client (>= 2.0.0),
21Recommends: ubuntuone-control-panel-gui21Recommends: ubuntuone-control-panel-gui
22Description: Ubuntu One Control Panel22Description: Ubuntu One Control Panel
23 Desktop application to manage an Ubuntu One account.23 Desktop application to manage an Ubuntu One account.
@@ -37,8 +37,8 @@
37 python-simplejson,37 python-simplejson,
38 python-twisted-core,38 python-twisted-core,
39 python-twisted-web,39 python-twisted-web,
40 python-ubuntuone-client (>= 1.7.1),40 python-ubuntuone-client (>= 2.0.0),
41 ubuntu-sso-client (>= 1.2.0),41 ubuntu-sso-client (>= 1.4.0),
42Description: Ubuntu One Control Panel Python Libraries42Description: Ubuntu One Control Panel Python Libraries
43 Ubuntu One Control Panel provides a Python library to manage an Ubuntu One43 Ubuntu One Control Panel provides a Python library to manage an Ubuntu One
44 account.44 account.
@@ -55,11 +55,11 @@
55 python-defer | python-aptdaemon,55 python-defer | python-aptdaemon,
56 python-gobject (>= 2.21.5),56 python-gobject (>= 2.21.5),
57 python-gtk2,57 python-gtk2,
58 python-ubuntuone-client (>= 1.7.1),58 python-ubuntuone-client (>= 2.0.0),
59 ubuntu-sso-client (>= 1.2.0),59 ubuntu-sso-client (>= 1.4.0),
60 ubuntuone-client (>= 1.7.1),60 ubuntuone-client (>= 2.0.0),
61 ubuntuone-control-panel (= ${binary:Version}),61 ubuntuone-control-panel (= ${binary:Version}),
62 ubuntuone-installer (>= 2.0.0),
62Provides: ubuntuone-control-panel-gui63Provides: ubuntuone-control-panel-gui
63Description: Ubuntu One Control Panel64Description: Ubuntu One Control Panel
64 GTK+ desktop application to manage an Ubuntu One account.65 GTK+ desktop application to manage an Ubuntu One account.
65
6666
=== modified file 'debian/ubuntuone-control-panel-gtk.install'
--- debian/ubuntuone-control-panel-gtk.install 2011-07-22 21:45:30 +0000
+++ debian/ubuntuone-control-panel-gtk.install 2011-09-26 18:38:27 +0000
@@ -1,7 +1,6 @@
1debian/tmp/usr/bin/ubuntuone-control-panel-gtk1debian/tmp/usr/bin/ubuntuone-control-panel-gtk
2debian/tmp/usr/share/dbus-1/services/com.ubuntuone.controlpanel.gui.service2debian/tmp/usr/share/dbus-1/services/com.ubuntuone.controlpanel.gui.service
3debian/tmp/usr/share/indicators/messages/applications/ubuntuone-control-panel3debian/tmp/usr/share/indicators/messages/applications/ubuntuone-control-panel
4debian/tmp/usr/share/applications/ubuntuone-control-panel-gtk.desktop
5debian/tmp/usr/share/ubuntuone-control-panel/gtk/*.ui4debian/tmp/usr/share/ubuntuone-control-panel/gtk/*.ui
6debian/tmp/usr/share/ubuntuone-control-panel/*.png5debian/tmp/usr/share/ubuntuone-control-panel/*.png
7debian/tmp/usr/share/man/man1/ubuntuone-control-panel-gtk.*6debian/tmp/usr/share/man/man1/ubuntuone-control-panel-gtk.*
87
=== modified file 'docs/ubuntuone-control-panel-gtk.1'
--- docs/ubuntuone-control-panel-gtk.1 2010-12-06 12:27:11 +0000
+++ docs/ubuntuone-control-panel-gtk.1 2011-09-26 18:38:27 +0000
@@ -1,7 +1,7 @@
1.TH UBUNTUONE-CONTROL-PANEL-GTK 11.TH UBUNTUONE-CONTROL-PANEL-GTK 1
22
3.SH NAME3.SH NAME
4ubuntuone-control-panel-gtk \- A GTK UI for managing a Ubuntu One account4ubuntuone-control-panel-gtk \- A GTK UI for managing an Ubuntu One account
55
6.SH SYNOPSYS6.SH SYNOPSYS
7.B ubutuone-control-panel-gtk7.B ubutuone-control-panel-gtk
@@ -9,7 +9,7 @@
9.SH DESCRIPTION9.SH DESCRIPTION
10This manual page briefly documents the10This manual page briefly documents the
11.BR ubuntuone-control-panel-gtk11.BR ubuntuone-control-panel-gtk
12process, which provides a desktop application to manage a Ubuntu One account.12process, which provides a desktop application to manage an Ubuntu One account.
1313
14.SH AUTHOR14.SH AUTHOR
15This manual page was written by Natalia Bidart <natalia.bidart@canonical.com>15This manual page was written by Natalia Bidart <natalia.bidart@canonical.com>
1616
=== modified file 'po/POTFILES.in'
--- po/POTFILES.in 2011-07-22 21:26:48 +0000
+++ po/POTFILES.in 2011-09-26 18:38:27 +0000
@@ -1,4 +1,3 @@
1ubuntuone-control-panel-gtk.desktop.in
2ubuntuone/controlpanel/gui/__init__.py1ubuntuone/controlpanel/gui/__init__.py
3[type: gettext/glade] data/gtk/dashboard.ui2[type: gettext/glade] data/gtk/dashboard.ui
4[type: gettext/glade] data/gtk/device.ui3[type: gettext/glade] data/gtk/device.ui
54
=== removed file 'po/ubuntuone-control-panel.pot'
--- po/ubuntuone-control-panel.pot 2011-08-25 19:37:14 +0000
+++ po/ubuntuone-control-panel.pot 1970-01-01 00:00:00 +0000
@@ -1,486 +0,0 @@
1# SOME DESCRIPTIVE TITLE.
2# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3# This file is distributed under the same license as the PACKAGE package.
4# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5#
6#, fuzzy
7msgid ""
8msgstr ""
9"Project-Id-Version: PACKAGE VERSION\n"
10"Report-Msgid-Bugs-To: \n"
11"POT-Creation-Date: 2011-08-25 15:26-0400\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"
15"Language: \n"
16"MIME-Version: 1.0\n"
17"Content-Type: text/plain; charset=CHARSET\n"
18"Content-Transfer-Encoding: 8bit\n"
19
20#: ../ubuntuone-control-panel-gtk.desktop.in.h:1
21msgid "Configure and manage your Ubuntu One account"
22msgstr ""
23
24#: ../ubuntuone/controlpanel/gui/__init__.py:72
25msgid "Always in sync"
26msgstr ""
27
28#: ../ubuntuone/controlpanel/gui/__init__.py:73
29msgid "Firefox extension"
30msgstr ""
31
32#: ../ubuntuone/controlpanel/gui/__init__.py:74
33msgid "Connect to Ubuntu One"
34msgstr ""
35
36#: ../ubuntuone/controlpanel/gui/__init__.py:75
37msgid "Evolution plug-in"
38msgstr ""
39
40#: ../ubuntuone/controlpanel/gui/__init__.py:76
41msgid "There was a problem while retrieving the credentials."
42msgstr ""
43
44#: ../ubuntuone/controlpanel/gui/__init__.py:77
45msgid "View your personal details and service summary"
46msgstr ""
47
48#: ../ubuntuone/controlpanel/gui/__init__.py:79
49msgid "Welcome to Ubuntu One!"
50msgstr ""
51
52#: ../ubuntuone/controlpanel/gui/__init__.py:80
53msgid ""
54"The information could not be retrieved. Maybe your internet connection is "
55"down?"
56msgstr ""
57
58#: ../ubuntuone/controlpanel/gui/__init__.py:83
59#: ../ubuntuone/controlpanel/gui/__init__.py:156
60msgid ""
61"The settings could not be changed,\n"
62"previous values were restored."
63msgstr ""
64
65#: ../ubuntuone/controlpanel/gui/__init__.py:85
66msgid "Are you sure you want to remove this device from Ubuntu One?"
67msgstr ""
68
69#: ../ubuntuone/controlpanel/gui/__init__.py:88
70msgid "The device could not be removed."
71msgstr ""
72
73#: ../ubuntuone/controlpanel/gui/__init__.py:89
74msgid "Manage devices registered with your personal cloud"
75msgstr ""
76
77#: ../ubuntuone/controlpanel/gui/__init__.py:91
78msgid "The devices connected with your personal cloud are listed below."
79msgstr ""
80
81#: ../ubuntuone/controlpanel/gui/__init__.py:93
82msgid "Explore"
83msgstr ""
84
85#: ../ubuntuone/controlpanel/gui/__init__.py:94
86#, python-format
87msgid "<i>%(package_name)s</i> could not be installed"
88msgstr ""
89
90#: ../ubuntuone/controlpanel/gui/__init__.py:95
91msgid "Sync another folder with your cloud"
92msgstr ""
93
94#: ../ubuntuone/controlpanel/gui/__init__.py:96
95#, python-format
96msgid ""
97"The chosen directory \"%(folder_path)s\" is not valid. \n"
98"\n"
99"Please choose a folder inside your \"%(home_folder)s\" directory, and not "
100"overlapping with any existing cloud folder."
101msgstr ""
102
103#: ../ubuntuone/controlpanel/gui/__init__.py:101
104msgid "My personal folders"
105msgstr ""
106
107#: ../ubuntuone/controlpanel/gui/__init__.py:102
108#, python-format
109msgid "Shared by %(other_user_display_name)s"
110msgstr ""
111
112#: ../ubuntuone/controlpanel/gui/__init__.py:103
113#, python-format
114msgid ""
115"The contents of your cloud folder will be merged with your local folder "
116"\"%(folder_path)s\" when subscribing.\n"
117"Do you want to subscribe to this cloud folder?"
118msgstr ""
119
120#: ../ubuntuone/controlpanel/gui/__init__.py:107
121msgid "Manage your cloud folders"
122msgstr ""
123
124#: ../ubuntuone/controlpanel/gui/__init__.py:109
125msgid ""
126"Select which folders from your cloud you want to sync with this computer"
127msgstr ""
128
129#: ../ubuntuone/controlpanel/gui/__init__.py:111
130msgid "Connect"
131msgstr ""
132
133#: ../ubuntuone/controlpanel/gui/__init__.py:112
134msgid "Connect the file sync service with your personal cloud"
135msgstr ""
136
137#: ../ubuntuone/controlpanel/gui/__init__.py:114
138msgid "File Sync is disabled."
139msgstr ""
140
141#: ../ubuntuone/controlpanel/gui/__init__.py:115
142msgid "Disconnect"
143msgstr ""
144
145#: ../ubuntuone/controlpanel/gui/__init__.py:116
146msgid "Disconnect the file sync service from your personal cloud"
147msgstr ""
148
149#: ../ubuntuone/controlpanel/gui/__init__.py:118
150msgid "File Sync is disconnected."
151msgstr ""
152
153#: ../ubuntuone/controlpanel/gui/__init__.py:119
154msgid "Enable"
155msgstr ""
156
157#: ../ubuntuone/controlpanel/gui/__init__.py:120
158msgid "Enable the file sync service"
159msgstr ""
160
161#: ../ubuntuone/controlpanel/gui/__init__.py:121
162msgid "File Sync error."
163msgstr ""
164
165#: ../ubuntuone/controlpanel/gui/__init__.py:122
166msgid "File Sync is up-to-date."
167msgstr ""
168
169#: ../ubuntuone/controlpanel/gui/__init__.py:123
170msgid "Restart"
171msgstr ""
172
173#: ../ubuntuone/controlpanel/gui/__init__.py:124
174msgid "Restart the file sync service"
175msgstr ""
176
177#: ../ubuntuone/controlpanel/gui/__init__.py:125
178msgid "File Sync"
179msgstr ""
180
181#: ../ubuntuone/controlpanel/gui/__init__.py:126
182msgid "Start"
183msgstr ""
184
185#: ../ubuntuone/controlpanel/gui/__init__.py:127
186msgid "Start the file sync service"
187msgstr ""
188
189#: ../ubuntuone/controlpanel/gui/__init__.py:128
190msgid "File Sync starting..."
191msgstr ""
192
193#: ../ubuntuone/controlpanel/gui/__init__.py:129
194msgid "Stop"
195msgstr ""
196
197#: ../ubuntuone/controlpanel/gui/__init__.py:130
198msgid "Stop the file sync service"
199msgstr ""
200
201#: ../ubuntuone/controlpanel/gui/__init__.py:131
202msgid "File Sync is stopped."
203msgstr ""
204
205#: ../ubuntuone/controlpanel/gui/__init__.py:132
206msgid "File Sync in progress..."
207msgstr ""
208
209#: ../ubuntuone/controlpanel/gui/__init__.py:133
210#, python-format
211msgid "%(free_space)s available storage"
212msgstr ""
213
214#: ../ubuntuone/controlpanel/gui/__init__.py:134
215#, python-format
216msgid "Hi %(user_display_name)s"
217msgstr ""
218
219#: ../ubuntuone/controlpanel/gui/__init__.py:135
220#, python-format
221msgid ""
222"You need to install the package <i>%(package_name)s</i> in order to enable "
223"more sync services."
224msgstr ""
225
226#: ../ubuntuone/controlpanel/gui/__init__.py:137
227#, python-format
228msgid "Install the %(plugin_name)s for the sync service: %(service_name)s"
229msgstr ""
230
231#: ../ubuntuone/controlpanel/gui/__init__.py:139
232#, python-format
233msgid "Installation of <i>%(package_name)s</i> in progress"
234msgstr ""
235
236#: ../ubuntuone/controlpanel/gui/__init__.py:140
237msgid "Loading..."
238msgstr ""
239
240#: ../ubuntuone/controlpanel/gui/__init__.py:141
241#, python-format
242msgid "%(app_name)s Control Panel"
243msgstr ""
244
245#: ../ubuntuone/controlpanel/gui/__init__.py:142
246msgid "My folders"
247msgstr ""
248
249#: ../ubuntuone/controlpanel/gui/__init__.py:143
250msgid "[unknown user name]"
251msgstr ""
252
253#: ../ubuntuone/controlpanel/gui/__init__.py:144
254msgid "Purchased Music"
255msgstr ""
256
257#: ../ubuntuone/controlpanel/gui/__init__.py:146
258#, python-format
259msgid "An internet connection is required to join or sign in to %(app_name)s."
260msgstr ""
261
262#: ../ubuntuone/controlpanel/gui/__init__.py:148
263msgid "No devices to show."
264msgstr ""
265
266#: ../ubuntuone/controlpanel/gui/__init__.py:149
267msgid "No folders to show."
268msgstr ""
269
270#: ../ubuntuone/controlpanel/gui/__init__.py:150
271msgid "There is no Ubuntu One pairing record."
272msgstr ""
273
274#: ../ubuntuone/controlpanel/gui/__init__.py:151
275#, python-format
276msgid "%(percentage)s used"
277msgstr ""
278
279#: ../ubuntuone/controlpanel/gui/__init__.py:152
280#, python-format
281msgid "Using %(used)s of %(total)s (%(percentage).0f%%)"
282msgstr ""
283
284#: ../ubuntuone/controlpanel/gui/__init__.py:153
285#, python-format
286msgid "%(used)s of %(total)s"
287msgstr ""
288
289#: ../ubuntuone/controlpanel/gui/__init__.py:154
290msgid "Manage the sync services"
291msgstr ""
292
293#: ../ubuntuone/controlpanel/gui/__init__.py:155
294msgid "Enable the sync services for this computer."
295msgstr ""
296
297#: ../ubuntuone/controlpanel/gui/__init__.py:158
298msgid "Manage the shares offered to others"
299msgstr ""
300
301#: ../ubuntuone/controlpanel/gui/__init__.py:159
302msgid "Manage permissions for shares made to other users."
303msgstr ""
304
305#: ../ubuntuone/controlpanel/gui/__init__.py:160
306#, python-format
307msgid "<i>%(package_name)s</i> was successfully installed"
308msgstr ""
309
310#: ../ubuntuone/controlpanel/gui/__init__.py:161 ../data/gtk/volumes.ui.h:1
311msgid "Sync locally?"
312msgstr ""
313
314#: ../ubuntuone/controlpanel/gui/__init__.py:162
315msgid "Value could not be retrieved."
316msgstr ""
317
318#: ../ubuntuone/controlpanel/gui/__init__.py:163
319msgid "Unknown error"
320msgstr ""
321
322#: ../data/gtk/dashboard.ui.h:1
323msgid "<b>Personal details</b>"
324msgstr ""
325
326#: ../data/gtk/dashboard.ui.h:2
327msgid "<b>Your services</b>"
328msgstr ""
329
330#: ../data/gtk/dashboard.ui.h:3
331msgid "Buy storage and plans"
332msgstr ""
333
334#: ../data/gtk/dashboard.ui.h:4
335msgid "Edit account details"
336msgstr ""
337
338#: ../data/gtk/device.ui.h:1
339msgid "KiB/s"
340msgstr ""
341
342#: ../data/gtk/device.ui.h:2
343msgid "Limit file sync bandwidth usage"
344msgstr ""
345
346#: ../data/gtk/device.ui.h:3
347msgid "Max download speed:"
348msgstr ""
349
350#: ../data/gtk/device.ui.h:4
351msgid "Max upload speed:"
352msgstr ""
353
354#: ../data/gtk/device.ui.h:5
355msgid "Show activity notifications"
356msgstr ""
357
358#: ../data/gtk/install.ui.h:1
359msgid "_Install now"
360msgstr ""
361
362#: ../data/gtk/management.ui.h:1
363msgid "Account"
364msgstr ""
365
366#: ../data/gtk/management.ui.h:2
367msgid "Cloud Folders"
368msgstr ""
369
370#: ../data/gtk/management.ui.h:3
371msgid "Community Support"
372msgstr ""
373
374#: ../data/gtk/management.ui.h:4
375msgid "Devices"
376msgstr ""
377
378#: ../data/gtk/management.ui.h:5
379msgid "Official Support"
380msgstr ""
381
382#: ../data/gtk/management.ui.h:6
383msgid "Services"
384msgstr ""
385
386#: ../data/gtk/management.ui.h:7
387msgid "Shares"
388msgstr ""
389
390#: ../data/gtk/management.ui.h:8
391msgid "Talk to us on:"
392msgstr ""
393
394#: ../data/gtk/management.ui.h:9
395msgid "http://twitter.com/ubuntuone"
396msgstr ""
397
398#: ../data/gtk/management.ui.h:10
399msgid "http://www.facebook.com/ubuntuone"
400msgstr ""
401
402#: ../data/gtk/overview.ui.h:1
403msgid ""
404"<span font=\"24\" foreground=\"#4d4d4d\">The Power of Your Personal Cloud</"
405"span>"
406msgstr ""
407
408#: ../data/gtk/overview.ui.h:2
409msgid "<span font_size=\"xx-large\" foreground=\"#4d4d4d\">Join now</span>"
410msgstr ""
411
412#: ../data/gtk/overview.ui.h:3
413msgid "<span foreground=\"#909090\">2GB of free storage</span>"
414msgstr ""
415
416#: ../data/gtk/overview.ui.h:4
417msgid "<span foreground=\"#909090\">Learn More</span>"
418msgstr ""
419
420#: ../data/gtk/overview.ui.h:5
421msgid ""
422"Files Anywhere\n"
423"<span foreground=\"#909090\">Back up and access your files from Ubuntu, "
424"Windows, Web or Mobile</span>"
425msgstr ""
426
427#: ../data/gtk/overview.ui.h:7
428msgid "I already have an account!"
429msgstr ""
430
431#: ../data/gtk/overview.ui.h:8
432msgid ""
433"Keep Connected\n"
434"<span foreground=\"#909090\">Unify your contacts across Desktop, Mobile and "
435"Web</span>"
436msgstr ""
437
438#: ../data/gtk/overview.ui.h:10
439msgid ""
440"Rock Out\n"
441"<span foreground=\"#909090\">Your entire collection follows you around with "
442"music streaming to Android and iPhone</span>"
443msgstr ""
444
445#: ../data/gtk/overview.ui.h:12
446msgid ""
447"Stay Productive\n"
448"<span foreground=\"#909090\">Keep your Firefox bookmarks and Tomboy notes "
449"synced</span>"
450msgstr ""
451
452#: ../data/gtk/services.ui.h:1
453msgid "<span font_size=\"small\">Bookmarks sync works with Firefox</span>"
454msgstr ""
455
456#: ../data/gtk/services.ui.h:2
457msgid ""
458"<span font_size=\"small\">Enable and then choose which folders you want to "
459"access from the Web or any device you connected to Ubuntu One\n"
460"\n"
461"Simply drag and drop any file or folder to your Ubuntu One folder on this "
462"computer</span>"
463msgstr ""
464
465#: ../data/gtk/services.ui.h:5
466msgid ""
467"<span font_size=\"small\">Once enabled, visit the <a href=\"https://one."
468"ubuntu.com\">Ubuntu One website</a> to manage your contacts, including Gmail "
469"and Facebook import</span>"
470msgstr ""
471
472#: ../data/gtk/services.ui.h:6
473msgid "Enable Bookmarks Sync"
474msgstr ""
475
476#: ../data/gtk/services.ui.h:7
477msgid "Enable Contacts Sync"
478msgstr ""
479
480#: ../data/gtk/services.ui.h:8
481msgid "Enable File Sync"
482msgstr ""
483
484#: ../data/gtk/services.ui.h:9
485msgid "_Show me my Ubuntu One folder"
486msgstr ""
4870
=== modified file 'setup.py'
--- setup.py 2011-08-25 19:37:14 +0000
+++ setup.py 2011-09-26 18:38:27 +0000
@@ -229,12 +229,12 @@
229229
230DistUtilsExtra.auto.setup(230DistUtilsExtra.auto.setup(
231 name='ubuntuone-control-panel',231 name='ubuntuone-control-panel',
232 version='1.1.3',232 version='2.0.0',
233 license='GPL v3',233 license='GPL v3',
234 author='Natalia Bidart',234 author='Natalia Bidart',
235 author_email='natalia.bidart@canonical.com',235 author_email='natalia.bidart@canonical.com',
236 description='Ubuntu One Control Panel',236 description='Ubuntu One Control Panel',
237 long_description='Application to manage a Ubuntu One account. Provides' \237 long_description='Application to manage an Ubuntu One account. Provides' \
238 ' a DBus service to query/modify all the Ubuntu One bits.',238 ' a DBus service to query/modify all the Ubuntu One bits.',
239 url='https://launchpad.net/ubuntuone-control-panel',239 url='https://launchpad.net/ubuntuone-control-panel',
240 packages=[240 packages=[
241241
=== removed file 'ubuntuone-control-panel-gtk.desktop.in'
--- ubuntuone-control-panel-gtk.desktop.in 2011-07-22 21:26:48 +0000
+++ ubuntuone-control-panel-gtk.desktop.in 1970-01-01 00:00:00 +0000
@@ -1,11 +0,0 @@
1[Desktop Entry]
2Name=Ubuntu One
3_Comment=Configure and manage your Ubuntu One account
4Exec=ubuntuone-control-panel-gtk
5Icon=ubuntuone
6Terminal=false
7Type=Application
8Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;X-GNOME-PersonalSettings
9StartupNotify=true
10X-Ayatana-Appmenu-Show-Stubs=False
11X-GNOME-Settings-Panel=ubuntuone
120
=== modified file 'ubuntuone-control-panel.in'
--- ubuntuone-control-panel.in 2011-01-27 22:10:30 +0000
+++ ubuntuone-control-panel.in 2011-09-26 18:38:27 +0000
@@ -1,1 +1,1 @@
1@prefix@/share/applications/ubuntuone-control-panel-gtk.desktop1@prefix@/share/applications/ubuntuone-installer.desktop
22
=== modified file 'ubuntuone/controlpanel/backend.py'
--- ubuntuone/controlpanel/backend.py 2011-08-25 19:37:14 +0000
+++ ubuntuone/controlpanel/backend.py 2011-09-26 18:38:27 +0000
@@ -67,8 +67,7 @@
67MSG_KEY = 'message'67MSG_KEY = 'message'
68STATUS_KEY = 'status'68STATUS_KEY = 'status'
6969
70BOOKMARKS_PKG = 'xul-ext-bindwood'70CONTACTS_PKG = 'thunderbird-couchdb'
71CONTACTS_PKG = 'evolution-couchdb'
7271
7372
74def append_path_sep(path):73def append_path_sep(path):
@@ -99,7 +98,7 @@
99 result = yield f(instance, *args, **kwargs)98 result = yield f(instance, *args, **kwargs)
100 except UnauthorizedError, e:99 except UnauthorizedError, e:
101 logger.exception('process_unauthorized (clearing credentials):')100 logger.exception('process_unauthorized (clearing credentials):')
102 yield instance.login_client.clear_credentials()101 yield instance.clear_credentials()
103 raise e102 raise e
104103
105 returnValue(result)104 returnValue(result)
@@ -138,6 +137,8 @@
138 self.sd_client = sd_client.SyncDaemonClient()137 self.sd_client = sd_client.SyncDaemonClient()
139 self.wc = web_client_factory(self.get_credentials)138 self.wc = web_client_factory(self.get_credentials)
140139
140 logger.info('ControlBackend: instance started.')
141
141 def _process_file_sync_status(self, status):142 def _process_file_sync_status(self, status):
142 """Process raw file sync status into custom format.143 """Process raw file sync status into custom format.
143144
@@ -297,16 +298,32 @@
297 @inlineCallbacks298 @inlineCallbacks
298 def get_credentials(self):299 def get_credentials(self):
299 """Find credentials."""300 """Find credentials."""
300 if self._credentials is None:301 if not self._credentials:
301 self._credentials = yield self.login_client.find_credentials()302 self._credentials = yield self.login_client.find_credentials()
302 returnValue(self._credentials)303 returnValue(self._credentials)
303304
304 @inlineCallbacks305 @inlineCallbacks
306 def clear_credentials(self):
307 """Clear the credentials."""
308 self._credentials = None
309 yield self.login_client.clear_credentials()
310
311 @inlineCallbacks
305 def get_token(self):312 def get_token(self):
306 """Return the token from the credentials."""313 """Return the token from the credentials."""
307 credentials = yield self.get_credentials()314 credentials = yield self.get_credentials()
308 returnValue(credentials["token"])315 returnValue(credentials["token"])
309316
317 @log_call(logger.debug, with_args=False)
318 @inlineCallbacks
319 def login(self, email, password):
320 """Login using 'email' and 'password'."""
321 result = yield self.login_client.login_email_password(
322 email=email, password=password)
323 # cache credentils
324 self._credentials = result
325 returnValue(result)
326
310 @inlineCallbacks327 @inlineCallbacks
311 def device_is_local(self, device_id):328 def device_is_local(self, device_id):
312 """Return whether 'device_id' is the local devicew or not."""329 """Return whether 'device_id' is the local devicew or not."""
@@ -480,7 +497,7 @@
480 if is_local:497 if is_local:
481 logger.warning('remove_device: device is local! removing and '498 logger.warning('remove_device: device is local! removing and '
482 'clearing credentials.')499 'clearing credentials.')
483 yield self.login_client.clear_credentials()500 yield self.clear_credentials()
484501
485 returnValue(device_id)502 returnValue(device_id)
486503
@@ -580,6 +597,7 @@
580 'list (%r).', vid, self._volumes[vid])597 'list (%r).', vid, self._volumes[vid])
581 self._volumes[vid] = share598 self._volumes[vid] = share
582599
600 share[u'realpath'] = share[u'path']
583 nicer_path = share[u'path'].replace(shares_dir, shares_dir_link)601 nicer_path = share[u'path'].replace(shares_dir, shares_dir_link)
584 share[u'path'] = nicer_path602 share[u'path'] = nicer_path
585 share[u'subscribed'] = bool(share[u'subscribed'])603 share[u'subscribed'] = bool(share[u'subscribed'])
@@ -690,9 +708,7 @@
690 result = []708 result = []
691 for rep in replications:709 for rep in replications:
692 dependency = ''710 dependency = ''
693 if rep == replication_client.BOOKMARKS:711 if rep == replication_client.CONTACTS:
694 dependency = BOOKMARKS_PKG
695 elif rep == replication_client.CONTACTS:
696 dependency = CONTACTS_PKG712 dependency = CONTACTS_PKG
697713
698 repd = {714 repd = {
@@ -717,18 +733,6 @@
717 returnValue(replication_id)733 returnValue(replication_id)
718734
719 @log_call(logger.debug)735 @log_call(logger.debug)
720 def query_bookmark_extension(self):
721 """True if the bookmark extension has been installed."""
722 # still pending (LP: #673672)
723 returnValue(False)
724
725 @log_call(logger.debug)
726 def install_bookmarks_extension(self):
727 """Install the extension to sync bookmarks."""
728 # still pending (LP: #673673)
729 returnValue(None)
730
731 @log_call(logger.debug)
732 @inlineCallbacks736 @inlineCallbacks
733 def file_sync_settings_info(self):737 def file_sync_settings_info(self):
734 """Get the file sync settings info."""738 """Get the file sync settings info."""
735739
=== added file 'ubuntuone/controlpanel/cache.py'
--- ubuntuone/controlpanel/cache.py 1970-01-01 00:00:00 +0000
+++ ubuntuone/controlpanel/cache.py 2011-09-26 18:38:27 +0000
@@ -0,0 +1,50 @@
1# -*- coding: utf-8 -*-
2
3# Authors: Natalia B Bidart <natalia.bidart@canonical.com>
4#
5# Copyright 2011 Canonical Ltd.
6#
7# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranties of
13# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14# PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program. If not, see <http://www.gnu.org/licenses/>.
18
19"""The base object that holds a backend instance."""
20
21from ubuntuone.controlpanel import backend
22
23
24class Cache(object):
25 """The base object that caches stuff."""
26
27 logger = None
28 _shared_objects = {}
29
30 def __init__(self, *args, **kwargs):
31 """Initialize the object using 'backend' as backend."""
32 super(Cache, self).__init__()
33 if self.logger is not None:
34 self.logger.debug('%s: started.', self.__class__.__name__)
35
36 def get_backend(self):
37 """A cached ControlBackend instance."""
38 if not self._shared_objects:
39 self._shared_objects['backend'] = backend.ControlBackend()
40 return self._shared_objects['backend']
41
42 def set_backend(self, new_value):
43 """Set a new ControlBackend instance."""
44 self._shared_objects['backend'] = new_value
45
46 backend = property(fget=get_backend, fset=set_backend)
47
48 def clear(self):
49 """Clear all cached objects."""
50 self._shared_objects = {}
051
=== modified file 'ubuntuone/controlpanel/dbus_service.py'
--- ubuntuone/controlpanel/dbus_service.py 2011-08-25 19:37:14 +0000
+++ ubuntuone/controlpanel/dbus_service.py 2011-09-26 18:38:27 +0000
@@ -563,46 +563,6 @@
563563
564 #---564 #---
565565
566 @log_call(logger.debug)
567 @method(dbus_interface=DBUS_PREFERENCES_IFACE, in_signature="")
568 def query_bookmark_extension(self):
569 """Check if the extension to sync bookmarks is installed."""
570 d = self.backend.query_bookmark_extension()
571 d.addCallback(self.QueryBookmarksResult)
572 d.addErrback(self.transform(self.QueryBookmarksError))
573
574 @log_call(logger.debug)
575 @signal(dbus_interface=DBUS_PREFERENCES_IFACE, signature="b")
576 def QueryBookmarksResult(self, enabled):
577 """The bookmark extension is or is not installed."""
578
579 @log_call(logger.error)
580 @signal(dbus_interface=DBUS_PREFERENCES_IFACE, signature="a{ss}")
581 def QueryBookmarksError(self, error):
582 """Problem getting the status of the extension."""
583
584 #---
585
586 @log_call(logger.info)
587 @method(dbus_interface=DBUS_PREFERENCES_IFACE, in_signature="")
588 def install_bookmarks_extension(self):
589 """Install the extension to sync bookmarks."""
590 d = self.backend.install_bookmarks_extension()
591 d.addCallback(lambda _: self.InstallBookmarksSuccess())
592 d.addErrback(self.transform(self.InstallBookmarksError))
593
594 @log_call(logger.info)
595 @signal(dbus_interface=DBUS_PREFERENCES_IFACE, signature="")
596 def InstallBookmarksSuccess(self):
597 """The extension to sync bookmarks has been installed."""
598
599 @log_call(logger.error)
600 @signal(dbus_interface=DBUS_PREFERENCES_IFACE, signature="a{ss}")
601 def InstallBookmarksError(self, error):
602 """Problem installing the extension to sync bookmarks."""
603
604 #---
605
606 @log_call(logger.info)566 @log_call(logger.info)
607 @method(dbus_interface=DBUS_PREFERENCES_IFACE, in_signature="")567 @method(dbus_interface=DBUS_PREFERENCES_IFACE, in_signature="")
608 def shutdown(self):568 def shutdown(self):
609569
=== modified file 'ubuntuone/controlpanel/dbustests/test_dbus_service.py'
--- ubuntuone/controlpanel/dbustests/test_dbus_service.py 2011-08-25 19:37:14 +0000
+++ ubuntuone/controlpanel/dbustests/test_dbus_service.py 2011-09-26 18:38:27 +0000
@@ -50,7 +50,7 @@
50 "limit_bandwidth": True,50 "limit_bandwidth": True,
51 "max_upload_speed": 12345,51 "max_upload_speed": 12345,
52 "max_download_speed": 54321,52 "max_download_speed": 54321,
53 "available_services": "files, contacts, music, bookmarks",53 "available_services": "files, contacts, music",
54 "enabled_services": "files, music",54 "enabled_services": "files, music",
55 },55 },
56 {56 {
@@ -59,8 +59,8 @@
59 "date_added": "2010-09-22T20:45:38.0",59 "date_added": "2010-09-22T20:45:38.0",
60 "type": "computer",60 "type": "computer",
61 "configurable": False,61 "configurable": False,
62 "available_services": "files, contacts, bookmarks",62 "available_services": "files, contacts",
63 "enabled_services": "files, bookmarks",63 "enabled_services": "files",
64 },64 },
65]65]
6666
@@ -244,14 +244,6 @@
244 """Configure a given replication."""244 """Configure a given replication."""
245 return self._process(replication_id)245 return self._process(replication_id)
246246
247 def query_bookmark_extension(self):
248 """True if the bookmark extension has been installed."""
249 return self._process(False)
250
251 def install_bookmarks_extension(self):
252 """Install the extension to sync bookmarks."""
253 return self._process(None)
254
255 def shutdown(self):247 def shutdown(self):
256 """Stop this service."""248 """Stop this service."""
257 self.shutdown_func()249 self.shutdown_func()
@@ -616,29 +608,6 @@
616 expected_replication_id, {'enabled': ''})608 expected_replication_id, {'enabled': ''})
617 return self.assert_correct_method_call(*args)609 return self.assert_correct_method_call(*args)
618610
619 def test_query_bookmarks_extension(self):
620 """The bookmarks extension is queried."""
621
622 def got_signal(enabled):
623 """The correct status was received."""
624 self.assertEqual(enabled, False)
625 self.deferred.callback("success")
626
627 args = ("QueryBookmarksResult", "QueryBookmarksError", got_signal,
628 self.backend.query_bookmark_extension)
629 return self.assert_correct_method_call(*args)
630
631 def test_install_bookmarks_extension(self):
632 """The bookmarks extension is installed."""
633
634 def got_signal():
635 """The extension was installed."""
636 self.deferred.callback("success")
637
638 args = ("InstallBookmarksSuccess", "InstallBookmarksError", got_signal,
639 self.backend.install_bookmarks_extension)
640 return self.assert_correct_method_call(*args)
641
642611
643class OperationsErrorTestCase(OperationsTestCase):612class OperationsErrorTestCase(OperationsTestCase):
644 """Test for the DBus service operations when there is an error."""613 """Test for the DBus service operations when there is an error."""
645614
=== modified file 'ubuntuone/controlpanel/gui/__init__.py'
--- ubuntuone/controlpanel/gui/__init__.py 2011-08-12 19:12:08 +0000
+++ ubuntuone/controlpanel/gui/__init__.py 2011-09-26 18:38:27 +0000
@@ -51,28 +51,29 @@
51MUSIC_STORE_ICON = 'music-store.png'51MUSIC_STORE_ICON = 'music-store.png'
52MUSIC_STREAM_ICON = 'music-stream.png'52MUSIC_STREAM_ICON = 'music-stream.png'
53NOTES_ICON = 'notes.png'53NOTES_ICON = 'notes.png'
54SERVICES_BOOKMARKS_ICON = 'services-bookmarks.png'
55SERVICES_CONTACTS_ICON = 'services-contacts.png'54SERVICES_CONTACTS_ICON = 'services-contacts.png'
56SERVICES_FILES_EXAMPLE = 'services-files-example.png'55SERVICES_FILES_EXAMPLE = 'services-files-example.png'
57SERVICES_FILES_ICON = 'services-files.png'56SERVICES_FILES_ICON = 'services-files.png'
5857
59FILE_URI_PREFIX = 'file://'58FILE_URI_PREFIX = 'file://'
59UBUNTUONE_FROM_OAUTH = 'https://one.ubuntu.com/api/1.0/from_oauth/'
60UBUNTUONE_LINK = 'https://one.ubuntu.com/'60UBUNTUONE_LINK = 'https://one.ubuntu.com/'
6161
62CONTACTS_LINK = UBUNTUONE_LINK62CONTACTS_LINK = UBUNTUONE_LINK
63EDIT_ACCOUNT_LINK = UBUNTUONE_LINK + 'account/'63EDIT_ACCOUNT_LINK = UBUNTUONE_LINK + 'account/'
64EDIT_DEVICES_LINK = EDIT_ACCOUNT_LINK + 'machines/'64EDIT_DEVICES_LINK = EDIT_ACCOUNT_LINK + 'machines/'
65EDIT_PROFILE_LINK = 'https://login.ubuntu.com/'65EDIT_PROFILE_LINK = 'https://login.ubuntu.com/'
66EDIT_SERVICES_LINK = UBUNTUONE_LINK + 'services'
66FACEBOOK_LINK = 'http://www.facebook.com/ubuntuone/'67FACEBOOK_LINK = 'http://www.facebook.com/ubuntuone/'
67GET_SUPPORT_LINK = UBUNTUONE_LINK + 'support/'68GET_SUPPORT_LINK = UBUNTUONE_LINK + 'support/'
68LEARN_MORE_LINK = UBUNTUONE_LINK69LEARN_MORE_LINK = UBUNTUONE_LINK
69MANAGE_FILES_LINK = UBUNTUONE_LINK + 'files/'70MANAGE_FILES_LINK = UBUNTUONE_LINK + 'files/'
71RESET_PASSWORD_LINK = EDIT_PROFILE_LINK + '+forgot_password'
70TWITTER_LINK = 'http://twitter.com/ubuntuone/'72TWITTER_LINK = 'http://twitter.com/ubuntuone/'
7173
72ALWAYS_SUBSCRIBED = _('Always in sync')74ALWAYS_SUBSCRIBED = _('Always in sync')
73BOOKMARKS = _('Firefox extension')
74CONNECT_BUTTON_LABEL = _('Connect to Ubuntu One')75CONNECT_BUTTON_LABEL = _('Connect to Ubuntu One')
75CONTACTS = _('Evolution plug-in')76CONTACTS = _('Thunderbird plug-in')
76CREDENTIALS_ERROR = _('There was a problem while retrieving the credentials.')77CREDENTIALS_ERROR = _('There was a problem while retrieving the credentials.')
77DASHBOARD_BUTTON_TOOLTIP = _('View your personal details and service '78DASHBOARD_BUTTON_TOOLTIP = _('View your personal details and service '
78 'summary')79 'summary')
@@ -188,9 +189,8 @@
188 credentials["consumer_secret"])189 credentials["consumer_secret"])
189 token = oauth.OAuthToken(credentials["token"],190 token = oauth.OAuthToken(credentials["token"],
190 credentials["token_secret"])191 credentials["token_secret"])
191 uri = 'https://one.ubuntu.com/api/1.0/from_oauth/'
192 request = oauth.OAuthRequest.from_consumer_and_token(192 request = oauth.OAuthRequest.from_consumer_and_token(
193 http_url=uri, http_method='GET',193 http_url=UBUNTUONE_FROM_OAUTH, http_method='GET',
194 oauth_consumer=consumer, token=token,194 oauth_consumer=consumer, token=token,
195 parameters={'next': url})195 parameters={'next': url})
196 sig_method = oauth.OAuthSignatureMethod_HMAC_SHA1()196 sig_method = oauth.OAuthSignatureMethod_HMAC_SHA1()
197197
=== modified file 'ubuntuone/controlpanel/gui/gtk/gui.py'
--- ubuntuone/controlpanel/gui/gtk/gui.py 2011-08-25 19:37:14 +0000
+++ ubuntuone/controlpanel/gui/gtk/gui.py 2011-09-26 18:38:27 +0000
@@ -62,7 +62,7 @@
62try:62try:
63 from gi.repository import Unity # pylint: disable=E061163 from gi.repository import Unity # pylint: disable=E0611
64 USE_LIBUNITY = True64 USE_LIBUNITY = True
65 U1_DOTDESKTOP = "ubuntuone-control-panel-gtk.desktop"65 U1_DOTDESKTOP = "ubuntuone-installer.desktop"
66except ImportError:66except ImportError:
67 USE_LIBUNITY = False67 USE_LIBUNITY = False
6868
@@ -71,6 +71,9 @@
7171
72WARNING_MARKUP = '<span foreground="%s"><b>%%s</b></span>' % ERROR_COLOR72WARNING_MARKUP = '<span foreground="%s"><b>%%s</b></span>' % ERROR_COLOR
7373
74CP_WMCLASS_NAME = 'ubuntuone-control-panel-gtk'
75CP_WMCLASS_CLASS = 'ubuntuone-installer'
76
7477
75def error_handler(*args, **kwargs):78def error_handler(*args, **kwargs):
76 """Log errors when calling D-Bus methods in a async way."""79 """Log errors when calling D-Bus methods in a async way."""
@@ -1118,11 +1121,8 @@
1118 self.files_icon.set_from_file(get_data_file(SERVICES_FILES_ICON))1121 self.files_icon.set_from_file(get_data_file(SERVICES_FILES_ICON))
1119 self.files_example.set_from_file(get_data_file(SERVICES_FILES_EXAMPLE))1122 self.files_example.set_from_file(get_data_file(SERVICES_FILES_EXAMPLE))
1120 self.contacts_icon.set_from_file(get_data_file(SERVICES_CONTACTS_ICON))1123 self.contacts_icon.set_from_file(get_data_file(SERVICES_CONTACTS_ICON))
1121 icon = get_data_file(SERVICES_BOOKMARKS_ICON)
1122 self.bookmarks_icon.set_from_file(icon)
11231124
1124 self.plugin_names = {'contacts': CONTACTS,1125 self.plugin_names = {'contacts': CONTACTS}
1125 'bookmarks': BOOKMARKS}
11261126
1127 self.package_manager = package_manager.PackageManager()1127 self.package_manager = package_manager.PackageManager()
1128 self.install_box = None1128 self.install_box = None
@@ -1161,13 +1161,6 @@
1161 """1161 """
1162 uri_hook(None, CONTACTS)1162 uri_hook(None, CONTACTS)
11631163
1164 def on_bookmarks_button_clicked(self, *args, **kwargs):
1165 """The bookmarks button was clicked.
1166
1167 XXX: this should be part of the DesktopcouchService widget.
1168
1169 """
1170
1171 @log_call(logger.debug)1164 @log_call(logger.debug)
1172 def load(self):1165 def load(self):
1173 """Load info."""1166 """Load info."""
@@ -1614,6 +1607,10 @@
1614 def __init__(self, switch_to='', alert=False):1607 def __init__(self, switch_to='', alert=False):
1615 super(ControlPanelWindow, self).__init__()1608 super(ControlPanelWindow, self).__init__()
16161609
1610 # We need to set WMCLASS so Unity falls back and we only get one
1611 # launcher on the launcher panel
1612 self.set_wmclass(CP_WMCLASS_NAME, CP_WMCLASS_CLASS)
1613
1617 self.connect('focus-in-event', self.remove_urgency)1614 self.connect('focus-in-event', self.remove_urgency)
1618 self.set_title(MAIN_WINDOW_TITLE % {'app_name': U1_APP_NAME})1615 self.set_title(MAIN_WINDOW_TITLE % {'app_name': U1_APP_NAME})
1619 self.set_position(gtk.WIN_POS_CENTER_ALWAYS)1616 self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
16201617
=== modified file 'ubuntuone/controlpanel/gui/gtk/tests/__init__.py'
--- ubuntuone/controlpanel/gui/gtk/tests/__init__.py 2011-08-25 19:37:14 +0000
+++ ubuntuone/controlpanel/gui/gtk/tests/__init__.py 2011-09-26 18:38:27 +0000
@@ -109,8 +109,8 @@
109 ]109 ]
110110
111111
112class FakeControlPanelBackend(FakedDBusBackend):112class FakedGUIBackend(FakedDBusBackend):
113 """Fake a Control Panel Service, act as a dbus.Interface."""113 """Fake a Control Panel GUI Service, act as a dbus.Interface."""
114114
115 bus_name = gui.DBUS_BUS_NAME_GUI115 bus_name = gui.DBUS_BUS_NAME_GUI
116 object_path = gui.DBUS_PATH_GUI116 object_path = gui.DBUS_PATH_GUI
@@ -135,7 +135,7 @@
135 return FakedControlPanelBackend(obj, dbus_interface,135 return FakedControlPanelBackend(obj, dbus_interface,
136 *args, **kwargs)136 *args, **kwargs)
137 if dbus_interface == gui.DBUS_IFACE_GUI:137 if dbus_interface == gui.DBUS_IFACE_GUI:
138 return FakeControlPanelBackend(138 return FakedGUIBackend(
139 obj, dbus_interface, *args, **kwargs)139 obj, dbus_interface, *args, **kwargs)
140140
141141
142142
=== modified file 'ubuntuone/controlpanel/gui/gtk/tests/test_gui_basic.py'
--- ubuntuone/controlpanel/gui/gtk/tests/test_gui_basic.py 2011-08-25 19:37:14 +0000
+++ ubuntuone/controlpanel/gui/gtk/tests/test_gui_basic.py 2011-09-26 18:38:27 +0000
@@ -122,6 +122,14 @@
122 self.assertEqual(122 self.assertEqual(
123 self._called, ((), {}), 'gtk.main_quit was not called.')123 self._called, ((), {}), 'gtk.main_quit was not called.')
124124
125 def test_wmclass_is_correct(self):
126 """Test that the WMCLASS is set."""
127 self.patch(gui.ControlPanelWindow, 'set_wmclass', self._set_called)
128 cp = gui.ControlPanelWindow()
129 cp.destroy()
130 expected = ((gui.CP_WMCLASS_NAME, gui.CP_WMCLASS_CLASS), {})
131 self.assertEqual(self._called, expected)
132
125 def test_title_is_correct(self):133 def test_title_is_correct(self):
126 """The window title is correct."""134 """The window title is correct."""
127 expected = gui.MAIN_WINDOW_TITLE % {'app_name': gui.U1_APP_NAME}135 expected = gui.MAIN_WINDOW_TITLE % {'app_name': gui.U1_APP_NAME}
@@ -315,7 +323,7 @@
315323
316324
317class UbuntuOneBinTestCase(BaseTestCase):325class UbuntuOneBinTestCase(BaseTestCase):
318 """The test suite for a Ubuntu One panel."""326 """The test suite for the Ubuntu One panel."""
319327
320 klass = gui.UbuntuOneBin328 klass = gui.UbuntuOneBin
321 kwargs = {'title': 'Something old, something new and something blue.'}329 kwargs = {'title': 'Something old, something new and something blue.'}
322330
=== modified file 'ubuntuone/controlpanel/gui/qt/__init__.py'
--- ubuntuone/controlpanel/gui/qt/__init__.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/__init__.py 2011-09-26 18:38:27 +0000
@@ -18,13 +18,25 @@
1818
19"""The Qt graphical interface for the control panel for Ubuntu One."""19"""The Qt graphical interface for the control panel for Ubuntu One."""
2020
21import collections
22import logging
23
24from functools import wraps
25
21from PyQt4 import QtGui, QtCore26from PyQt4 import QtGui, QtCore
27from twisted.internet import defer
28
29from ubuntuone.controlpanel.gui import FILE_URI_PREFIX
2230
2331
24def uri_hook(uri):32def uri_hook(uri):
25 """Open an URI using the default browser/file manager."""33 """Open an URI using the default browser/file manager."""
26 url = QtCore.QString(uri)34 if uri.startswith(FILE_URI_PREFIX):
27 QtGui.QDesktopServices.openUrl(QtCore.QUrl(url))35 url = QtCore.QUrl(uri)
36 else:
37 url = QtCore.QUrl()
38 url.setEncodedUrl(uri)
39 QtGui.QDesktopServices.openUrl(url)
2840
2941
30def pixmap_from_name(icon_name):42def pixmap_from_name(icon_name):
@@ -52,3 +64,46 @@
52 icon.icon_name = icon_name64 icon.icon_name = icon_name
5365
54 return icon66 return icon
67
68
69def handle_errors(error_handler=None, logger=None):
70 """Decorator to handle errors when calling a function.
71
72 if 'error_handler' is not None, it will be yielded on if any error happens.
73
74 """
75 if logger is None:
76 logger = logging.getLogger()
77
78 def middle(f):
79 """Decorator to handle errors when calling 'f'."""
80
81 @defer.inlineCallbacks
82 @wraps(f)
83 def inner(*args, **kwargs):
84 """Call 'f' passing 'args' and 'kwargs'.
85
86 Catch any error and show a error message.
87
88 """
89 try:
90 res = yield f(*args, **kwargs)
91 except Exception, e: # pylint: disable=W0703
92 logger.exception(f.__name__)
93 else:
94 defer.returnValue(res)
95
96 # this code will only be executed if there was an exception
97 if error_handler is not None:
98 yield error_handler()
99
100 if len(e.args) > 0 and isinstance(e.args[0], collections.Mapping):
101 msgs = e.args[0].itervalues()
102 else:
103 msgs = [e.__class__.__name__] + map(repr, e.args)
104 msg = '\n'.join(msgs)
105 QtGui.QMessageBox.warning(None, '', msg, QtGui.QMessageBox.Close)
106
107 return inner
108
109 return middle
55110
=== modified file 'ubuntuone/controlpanel/gui/qt/account.py'
--- ubuntuone/controlpanel/gui/qt/account.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/account.py 2011-09-26 18:38:27 +0000
@@ -37,12 +37,15 @@
37 """The Account Tab Panel widget"""37 """The Account Tab Panel widget"""
3838
39 ui_class = account_ui39 ui_class = account_ui
40 logger = logger
4041
41 def _setup(self):42 def _setup(self):
42 """Do some extra setupping for the UI."""43 """Do some extra setupping for the UI."""
44 super(AccountPanel, self)._setup()
43 self.ui.edit_profile_button.uri = EDIT_PROFILE_LINK45 self.ui.edit_profile_button.uri = EDIT_PROFILE_LINK
44 self.ui.edit_services_button.uri = EDIT_ACCOUNT_LINK46 self.ui.edit_services_button.uri = EDIT_ACCOUNT_LINK
4547
48 # pylint: disable=E0202
46 @defer.inlineCallbacks49 @defer.inlineCallbacks
47 def load(self):50 def load(self):
48 """Load info."""51 """Load info."""
4952
=== modified file 'ubuntuone/controlpanel/gui/qt/addfolder.py'
--- ubuntuone/controlpanel/gui/qt/addfolder.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/addfolder.py 2011-09-26 18:38:27 +0000
@@ -25,11 +25,10 @@
25from PyQt4 import QtGui, QtCore25from PyQt4 import QtGui, QtCore
26from twisted.internet import defer26from twisted.internet import defer
2727
28from ubuntuone.controlpanel import backend28from ubuntuone.controlpanel import cache
29from ubuntuone.controlpanel.logger import setup_logging29from ubuntuone.controlpanel.logger import setup_logging
30from ubuntuone.controlpanel.gui import (30from ubuntuone.controlpanel.gui import FOLDER_INVALID_PATH
31 FOLDER_INVALID_PATH,31from ubuntuone.controlpanel.gui.qt import handle_errors
32)
3332
3433
35logger = setup_logging('qt.addfolder')34logger = setup_logging('qt.addfolder')
@@ -37,9 +36,11 @@
37CLOSE = QtGui.QMessageBox.Close36CLOSE = QtGui.QMessageBox.Close
3837
3938
40class AddFolderButton(QtGui.QPushButton):39class AddFolderButton(cache.Cache, QtGui.QPushButton):
41 """The AddFolderButton widget"""40 """The AddFolderButton widget"""
4241
42 logger = logger
43
43 folderCreated = QtCore.pyqtSignal(unicode)44 folderCreated = QtCore.pyqtSignal(unicode)
44 folderCreationCanceled = QtCore.pyqtSignal()45 folderCreationCanceled = QtCore.pyqtSignal()
4546
@@ -47,16 +48,17 @@
47 """Initialize the UI of the widget."""48 """Initialize the UI of the widget."""
48 super(AddFolderButton, self).__init__(*args, **kwargs)49 super(AddFolderButton, self).__init__(*args, **kwargs)
49 self.cloud_folders = []50 self.cloud_folders = []
50 self.backend = backend.ControlBackend()
51 self.clicked.connect(self.on_clicked)51 self.clicked.connect(self.on_clicked)
52 logger.debug('%s: started.', self.__class__.__name__)
5352
54 @QtCore.pyqtSlot()53 @QtCore.pyqtSlot()
54 @handle_errors(logger=logger)
55 @defer.inlineCallbacks55 @defer.inlineCallbacks
56 def on_clicked(self):56 def on_clicked(self):
57 """The 'Sync another folder' button was clicked."""57 """The 'Sync another folder' button was clicked."""
58 folder = QtGui.QFileDialog.getExistingDirectory(parent=self)58 # The options argument is because of LP: #835013
59 folder = unicode(folder)59 folder = QtGui.QFileDialog.getExistingDirectory(
60 parent=self, options=QtGui.QFileDialog.DontUseNativeDialog)
61 folder = unicode(QtCore.QDir.toNativeSeparators(folder))
60 logger.debug('on_add_folder_button_clicked: user requested folder '62 logger.debug('on_add_folder_button_clicked: user requested folder '
61 'creation for path %r', folder)63 'creation for path %r', folder)
62 if folder == '':64 if folder == '':
6365
=== modified file 'ubuntuone/controlpanel/gui/qt/controlpanel.py'
--- ubuntuone/controlpanel/gui/qt/controlpanel.py 2011-08-12 19:12:08 +0000
+++ ubuntuone/controlpanel/gui/qt/controlpanel.py 2011-09-26 18:38:27 +0000
@@ -21,62 +21,79 @@
2121
22from __future__ import division22from __future__ import division
2323
24from PyQt4 import QtGui, QtCore24from PyQt4 import QtCore
25from twisted.internet import defer25from twisted.internet import defer
2626
27from ubuntuone.controlpanel import backend27from ubuntuone.controlpanel.backend import AUTOCONNECT_KEY
28from ubuntuone.controlpanel.logger import setup_logging, log_call28from ubuntuone.controlpanel.logger import setup_logging, log_call
29from ubuntuone.controlpanel.gui import (29from ubuntuone.controlpanel.gui import (
30 humanize,30 humanize,
31 EDIT_ACCOUNT_LINK,31 EDIT_SERVICES_LINK,
32 FACEBOOK_LINK,32 FACEBOOK_LINK,
33 GET_SUPPORT_LINK,33 GET_SUPPORT_LINK,
34 GREETING,34 GREETING,
35 PERCENTAGE_LABEL,35 PERCENTAGE_LABEL,
36 QUOTA_THRESHOLD,
36 TWITTER_LINK,37 TWITTER_LINK,
37 USAGE_LABEL,38 USAGE_LABEL,
38)39)
39from ubuntuone.controlpanel.gui.qt import uri_hook40from ubuntuone.controlpanel.gui import qt
41from ubuntuone.controlpanel.gui.qt.ubuntuonebin import UbuntuOneBin
40from ubuntuone.controlpanel.gui.qt.ui import controlpanel_ui42from ubuntuone.controlpanel.gui.qt.ui import controlpanel_ui
4143
4244
43logger = setup_logging('qt.controlpanel')45logger = setup_logging('qt.controlpanel')
4446
45NAME_STYLE = '<br><span style=" font-size:24pt;">%s!</span>'47NAME_STYLE = '<br><span style=" font-size:16pt;">%s!</span>'
46PERCENTAGE_STYLE = '<span style=" font-size:16pt;">%.0f%%</span>'48PERCENTAGE_STYLE = '<span style=" font-size:16pt;">%.0f%%</span>'
4749
4850
49class ControlPanel(QtGui.QWidget):51class ControlPanel(UbuntuOneBin):
50 """The Control Panel widget"""52 """The Control Panel widget"""
5153
52 def __init__(self, parent=None):54 ui_class = controlpanel_ui
53 """Initialize the UI of the widget."""55 logger = logger
54 QtGui.QWidget.__init__(self, parent)
55 self.ui = controlpanel_ui.Ui_Form()
56 self.ui.setupUi(self)
57
58 self.backend = backend.ControlBackend()
59 self._setup()
60 logger.debug('%s: started.', self.__class__.__name__)
6156
62 def _setup(self):57 def _setup(self):
63 """Do some extra setupping for the UI."""58 """Do some extra setupping for the UI."""
64 self.ui.get_more_space_button.uri = EDIT_ACCOUNT_LINK59 self.ui.get_more_space_button.uri = EDIT_SERVICES_LINK
65 self.ui.help_button.uri = GET_SUPPORT_LINK60 self.ui.help_button.uri = GET_SUPPORT_LINK
6661 self.ui.devices_tab.localDeviceRemoved.connect(
67 # Invalid name "showEvent"62 self.on_credentials_not_found)
68 # pylint: disable=C010363 self.ui.signin.credentialsFound.connect(lambda creds: self.load())
6964
70 def showEvent(self, event):65 @defer.inlineCallbacks
71 """Load info."""66 def connect_file_sync(self):
72 self.load()67 """Connect file sync service if the setting autoconnect is enabled."""
73 event.accept()68 settings = yield self.backend.file_sync_settings_info()
7469 if AUTOCONNECT_KEY in settings and settings[AUTOCONNECT_KEY]:
70 yield self.backend.connect_files()
71
72 @log_call(logger.debug)
73 def on_credentials_not_found(self):
74 """Credentials are not found or were removed."""
75 self.ui.switcher.setCurrentWidget(self.ui.signin)
76 self.is_processing = False
77
78 @log_call(logger.debug)
79 def on_credentials_found(self):
80 """Credentials are not found or were removed."""
81 self.ui.switcher.setCurrentWidget(self.ui.management)
82 self.connect_file_sync()
83 self.is_processing = False
84
85 # pylint: disable=E0202
75 @defer.inlineCallbacks86 @defer.inlineCallbacks
76 def load(self):87 def load(self):
77 """Load info."""88 """Load info."""
78 info = yield self.backend.account_info()89 self.is_processing = True
79 self.process_info(info)90 credentials = yield self.backend.get_credentials()
91 if not credentials:
92 self.on_credentials_not_found()
93 else:
94 self.on_credentials_found()
95 info = yield self.backend.account_info()
96 self.process_info(info)
8097
81 @log_call(logger.debug)98 @log_call(logger.debug)
82 def process_info(self, info):99 def process_info(self, info):
@@ -86,17 +103,43 @@
86103
87 used = int(info['quota_used'])104 used = int(info['quota_used'])
88 total = int(info['quota_total'])105 total = int(info['quota_total'])
89 percentage = {'percentage': PERCENTAGE_STYLE % ((used / total) * 100)}106 percentage_value = ((used / total) * 100)
107 percentage = {'percentage': PERCENTAGE_STYLE % percentage_value}
90 data = {'used': humanize(used), 'total': humanize(total)}108 data = {'used': humanize(used), 'total': humanize(total)}
91 self.ui.percentage_usage_label.setText(PERCENTAGE_LABEL % percentage)109 self.ui.percentage_usage_label.setText(PERCENTAGE_LABEL % percentage)
92 self.ui.quota_usage_label.setText(USAGE_LABEL % data)110 self.ui.quota_usage_label.setText(USAGE_LABEL % data)
111 self._update_quota({'percentage': percentage_value})
112
113 @log_call(logger.debug)
114 def _update_quota(self, data=None):
115 """Update the quota info."""
116 fraction = 0.0
117 if data is not None:
118 fraction = data.get('percentage', 0.0) / 100
119 if fraction > 0 and fraction < 0.05:
120 fraction = 0.05
121 else:
122 fraction = round(fraction, 2)
123
124 logger.debug('ManagementPanel: updating quota to %r.', fraction)
125 self.ui.percentage_usage_label.setProperty("OverQuota",
126 fraction >= QUOTA_THRESHOLD)
127 self.ui.quota_usage_label.setProperty("OverQuota",
128 fraction >= QUOTA_THRESHOLD)
129 self.ui.percentage_usage_label.style().unpolish(
130 self.ui.percentage_usage_label)
131 self.ui.percentage_usage_label.style().polish(
132 self.ui.percentage_usage_label)
133 self.ui.quota_usage_label.style().unpolish(
134 self.ui.quota_usage_label)
135 self.ui.quota_usage_label.style().polish(self.ui.quota_usage_label)
93136
94 @QtCore.pyqtSlot()137 @QtCore.pyqtSlot()
95 def on_twitter_button_clicked(self):138 def on_twitter_button_clicked(self):
96 """The twitter button was clicked."""139 """The twitter button was clicked."""
97 uri_hook(TWITTER_LINK)140 qt.uri_hook(TWITTER_LINK)
98141
99 @QtCore.pyqtSlot()142 @QtCore.pyqtSlot()
100 def on_facebook_button_clicked(self):143 def on_facebook_button_clicked(self):
101 """The facebook button was clicked."""144 """The facebook button was clicked."""
102 uri_hook(FACEBOOK_LINK)145 qt.uri_hook(FACEBOOK_LINK)
103146
=== modified file 'ubuntuone/controlpanel/gui/qt/device.py'
--- ubuntuone/controlpanel/gui/qt/device.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/device.py 2011-09-26 18:38:27 +0000
@@ -25,9 +25,15 @@
25 DEVICE_TYPE_COMPUTER,25 DEVICE_TYPE_COMPUTER,
26 DEVICE_TYPE_PHONE,26 DEVICE_TYPE_PHONE,
27)27)
28from ubuntuone.controlpanel import cache
28from ubuntuone.controlpanel.gui import DEVICE_CONFIRM_REMOVE29from ubuntuone.controlpanel.gui import DEVICE_CONFIRM_REMOVE
29from ubuntuone.controlpanel.gui.qt import icon_from_name, pixmap_from_name30from ubuntuone.controlpanel.gui.qt import (
31 handle_errors,
32 icon_from_name,
33 pixmap_from_name,
34)
30from ubuntuone.controlpanel.gui.qt.ui import device_ui35from ubuntuone.controlpanel.gui.qt.ui import device_ui
36from ubuntuone.controlpanel.logger import setup_logging
3137
32COMPUTER_ICON = "computer"38COMPUTER_ICON = "computer"
33PHONE_ICON = "phone"39PHONE_ICON = "phone"
@@ -43,25 +49,27 @@
43YES = QtGui.QMessageBox.Yes49YES = QtGui.QMessageBox.Yes
4450
4551
52logger = setup_logging('qt.device')
53
54
46def icon_name_from_type(device_type):55def icon_name_from_type(device_type):
47 """Get the icon name for the device."""56 """Get the icon name for the device."""
48 icon_name = DEVICE_TYPE_TO_ICON_MAP.get(device_type, DEFAULT_ICON)57 icon_name = DEVICE_TYPE_TO_ICON_MAP.get(device_type, DEFAULT_ICON)
49 return icon_name58 return icon_name
5059
5160
52class DeviceWidget(QtGui.QWidget):61class DeviceWidget(cache.Cache, QtGui.QWidget):
53 """The widget for each device in the control panel."""62 """The widget for each device in the control panel."""
5463
55 removed = QtCore.pyqtSignal()64 removed = QtCore.pyqtSignal()
56 removeCanceled = QtCore.pyqtSignal()65 removeCanceled = QtCore.pyqtSignal()
5766
58 def __init__(self, backend, device_id, **kwargs):67 def __init__(self, device_id, *args, **kwargs):
59 """Initialize the UI of the widget."""68 """Initialize the UI of the widget."""
60 QtGui.QWidget.__init__(self, **kwargs)69 super(DeviceWidget, self).__init__(*args, **kwargs)
61 self.ui = device_ui.Ui_Form()70 self.ui = device_ui.Ui_Form()
62 self.ui.setupUi(self)71 self.ui.setupUi(self)
63 self.id = device_id72 self.id = device_id
64 self.backend = backend
6573
66 def update_device_info(self, device_info):74 def update_device_info(self, device_info):
67 """Update the device info."""75 """Update the device info."""
@@ -70,8 +78,9 @@
70 pixmap = pixmap_from_name(icon_name)78 pixmap = pixmap_from_name(icon_name)
71 self.ui.device_icon_label.setPixmap(pixmap)79 self.ui.device_icon_label.setPixmap(pixmap)
7280
81 @QtCore.pyqtSlot()
82 @handle_errors(logger=logger)
73 @defer.inlineCallbacks83 @defer.inlineCallbacks
74 @QtCore.pyqtSlot()
75 def on_remove_device_button_clicked(self):84 def on_remove_device_button_clicked(self):
76 """The user wants to remove this device."""85 """The user wants to remove this device."""
77 msg = DEVICE_CONFIRM_REMOVE86 msg = DEVICE_CONFIRM_REMOVE
7887
=== modified file 'ubuntuone/controlpanel/gui/qt/devices.py'
--- ubuntuone/controlpanel/gui/qt/devices.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/devices.py 2011-09-26 18:38:27 +0000
@@ -18,8 +18,6 @@
1818
19"""The user interface for the control panel for Ubuntu One."""19"""The user interface for the control panel for Ubuntu One."""
2020
21from gettext import gettext as _
22
23# Unused import QtGui21# Unused import QtGui
24# pylint: disable=W061122# pylint: disable=W0611
25from PyQt4 import QtGui, QtCore23from PyQt4 import QtGui, QtCore
@@ -39,13 +37,17 @@
39class DevicesPanel(UbuntuOneBin):37class DevicesPanel(UbuntuOneBin):
40 """The DevicesFolders Tab Panel widget"""38 """The DevicesFolders Tab Panel widget"""
4139
42 title = _('This device')
43 ui_class = devices_ui40 ui_class = devices_ui
41 logger = logger
42
43 localDeviceRemoved = QtCore.pyqtSignal()
4444
45 def _setup(self):45 def _setup(self):
46 """Do some extra setupping for the UI."""46 """Do some extra setupping for the UI."""
47 super(DevicesPanel, self)._setup()
47 self.ui.manage_devices_button.uri = EDIT_DEVICES_LINK48 self.ui.manage_devices_button.uri = EDIT_DEVICES_LINK
4849
50 # pylint: disable=E0202
49 @defer.inlineCallbacks51 @defer.inlineCallbacks
50 def load(self):52 def load(self):
51 """Load info."""53 """Load info."""
@@ -64,6 +66,11 @@
6466
65 self.is_processing = False67 self.is_processing = False
6668
69 def on_local_device_removed(self):
70 """When the local device is removed, clear the box and emit signal."""
71 self.clear_device_info(self.ui.local_device_box)
72 self.localDeviceRemoved.emit()
73
67 def clear_device_info(self, box):74 def clear_device_info(self, box):
68 """Clear all the device info."""75 """Clear all the device info."""
69 children = box.count()76 children = box.count()
@@ -84,11 +91,9 @@
8491
85 def update_local_device(self, device_info):92 def update_local_device(self, device_info):
86 """Update the info for the local device."""93 """Update the info for the local device."""
87 device_widget = device.DeviceWidget(backend=self.backend,94 device_widget = device.DeviceWidget(device_id=device_info['device_id'])
88 device_id=device_info['device_id'])
89 device_widget.update_device_info(device_info)95 device_widget.update_device_info(device_info)
90 f = lambda: self.clear_device_info(self.ui.local_device_box)96 device_widget.removed.connect(self.on_local_device_removed)
91 device_widget.removed.connect(f)
9297
93 self.ui.local_device_box.addWidget(device_widget)98 self.ui.local_device_box.addWidget(device_widget)
9499
95100
=== modified file 'ubuntuone/controlpanel/gui/qt/filesyncstatus.py'
--- ubuntuone/controlpanel/gui/qt/filesyncstatus.py 2011-08-25 19:37:14 +0000
+++ ubuntuone/controlpanel/gui/qt/filesyncstatus.py 2011-09-26 18:38:27 +0000
@@ -21,7 +21,7 @@
21from PyQt4 import QtGui, QtCore21from PyQt4 import QtGui, QtCore
22from twisted.internet import defer22from twisted.internet import defer
2323
24from ubuntuone.controlpanel import backend24from ubuntuone.controlpanel import backend, cache
25from ubuntuone.controlpanel.logger import setup_logging, log_call25from ubuntuone.controlpanel.logger import setup_logging, log_call
26from ubuntuone.controlpanel.gui import (26from ubuntuone.controlpanel.gui import (
27 ERROR_COLOR,27 ERROR_COLOR,
@@ -108,27 +108,26 @@
108 return icon_name108 return icon_name
109109
110110
111class FileSyncStatus(QtGui.QWidget):111class FileSyncStatus(cache.Cache, QtGui.QWidget):
112 """The FileSyncStatus widget"""112 """The FileSyncStatus widget"""
113113
114 def __init__(self, parent=None):114 def __init__(self, *args, **kwargs):
115 """Initialize the UI of the widget."""115 """Initialize the UI of the widget."""
116 QtGui.QWidget.__init__(self, parent)116 super(FileSyncStatus, self).__init__(*args, **kwargs)
117 self.ui = filesyncstatus_ui.Ui_Form()117 self.ui = filesyncstatus_ui.Ui_Form()
118 self.ui.setupUi(self)118 self.ui.setupUi(self)
119119
120 self._backend_method = None120 self._backend_method = None
121 self.backend = backend.ControlBackend()
122
123 logger.debug('%s: started.', self.__class__.__name__)
124121
125 # Invalid name "showEvent"122 # Invalid name "showEvent"
126 # pylint: disable=C0103123 # pylint: disable=C0103
127124
128 def showEvent(self, event):125 def showEvent(self, event):
129 """Load info."""126 """Load info."""
127 super(FileSyncStatus, self).showEvent(event)
130 self.load()128 self.load()
131 event.accept()129
130 # pylint: enable=C0103
132131
133 @defer.inlineCallbacks132 @defer.inlineCallbacks
134 def load(self):133 def load(self):
135134
=== modified file 'ubuntuone/controlpanel/gui/qt/folders.py'
--- ubuntuone/controlpanel/gui/qt/folders.py 2011-08-12 19:12:08 +0000
+++ ubuntuone/controlpanel/gui/qt/folders.py 2011-09-26 18:38:27 +0000
@@ -29,7 +29,6 @@
29from ubuntuone.controlpanel.gui import (29from ubuntuone.controlpanel.gui import (
30 ALWAYS_SUBSCRIBED,30 ALWAYS_SUBSCRIBED,
31 EXPLORE,31 EXPLORE,
32 FILE_URI_PREFIX,
33 FOLDER_ICON_NAME,32 FOLDER_ICON_NAME,
34 FOLDER_OWNED_BY,33 FOLDER_OWNED_BY,
35 FOLDER_SHARED_BY,34 FOLDER_SHARED_BY,
@@ -65,11 +64,12 @@
65 """The Folders Tab Panel widget"""64 """The Folders Tab Panel widget"""
6665
67 ui_class = folders_ui66 ui_class = folders_ui
67 logger = logger
6868
69 def _setup(self):69 def _setup(self):
70 """Do some extra setupping for the UI."""70 """Do some extra setupping for the UI."""
71 load_info = lambda *a, **kw: self.load()71 super(FoldersPanel, self)._setup()
72 self.ui.add_folder_button.folderCreated.connect(load_info)72 self.ui.add_folder_button.folderCreated.connect(self.on_folder_created)
7373
74 headers = self.ui.folders.header()74 headers = self.ui.folders.header()
75 headers.setResizeMode(FOLDER_NAME_COL, headers.Stretch)75 headers.setResizeMode(FOLDER_NAME_COL, headers.Stretch)
@@ -81,8 +81,16 @@
81 icon = icon_from_name('external_icon_orange')81 icon = icon_from_name('external_icon_orange')
82 self.ui.share_publish_button.setIcon(icon)82 self.ui.share_publish_button.setIcon(icon)
8383
84 logger.debug('%s: started.', self.__class__.__name__)84 @log_call(logger.info)
85 def on_folder_created(self, new_folder):
86 """Reload folder info after folder creation."""
87 self.is_processing = True
88 # hack to ensure that syncdaemon updates the folder list.
89 # pylint: disable=W0404, E1101
90 from twisted.internet import reactor
91 reactor.callLater(2, self.load)
8592
93 # pylint: disable=E0202
86 @defer.inlineCallbacks94 @defer.inlineCallbacks
87 def load(self):95 def load(self):
88 """Load specific tab info."""96 """Load specific tab info."""
@@ -124,9 +132,15 @@
124 self.ui.folders.addTopLevelItem(item)132 self.ui.folders.addTopLevelItem(item)
125133
126 for volume in volumes:134 for volume in volumes:
135 is_root = volume[u'type'] == self.backend.ROOT_TYPE
136 is_share = volume[u'type'] == self.backend.SHARE_TYPE
137
127 child = QtGui.QTreeWidgetItem()138 child = QtGui.QTreeWidgetItem()
128 child.setSizeHint(FOLDER_NAME_COL, QtCore.QSize(-1, 35))139 child.setSizeHint(FOLDER_NAME_COL, QtCore.QSize(-1, 35))
129 child.volume_path = volume['path']140 if is_share and 'realpath' in volume:
141 child.volume_path = volume['realpath']
142 else:
143 child.volume_path = volume['path']
130 child.volume_id = volume['volume_id']144 child.volume_id = volume['volume_id']
131145
132 name = self._process_name(volume[u'display_name'])146 name = self._process_name(volume[u'display_name'])
@@ -134,9 +148,6 @@
134 child.setToolTip(FOLDER_NAME_COL, name)148 child.setToolTip(FOLDER_NAME_COL, name)
135 child.setToolTip(EXPLORE_COL, EXPLORE)149 child.setToolTip(EXPLORE_COL, EXPLORE)
136150
137 is_root = volume[u'type'] == self.backend.ROOT_TYPE
138 is_share = volume[u'type'] == self.backend.SHARE_TYPE
139
140 icon_name = FOLDER_ICON_NAME151 icon_name = FOLDER_ICON_NAME
141 if is_share:152 if is_share:
142 icon_name = SHARE_ICON_NAME153 icon_name = SHARE_ICON_NAME
@@ -173,12 +184,14 @@
173 policy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,184 policy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,
174 QtGui.QSizePolicy.Fixed)185 QtGui.QSizePolicy.Fixed)
175 button.setSizePolicy(policy)186 button.setSizePolicy(policy)
187 button.setEnabled(bool(volume[u'subscribed']))
176188
177 # Operator not preceded by a space189 # Operator not preceded by a space
178 # pylint: disable=C0322190 # pylint: disable=C0322
179 cb = lambda item=child: self.on_folders_itemActivated(item)191 cb = lambda checked, item=child: \
192 self.on_folders_itemActivated(item)
180 # pylint: enable=C0322193 # pylint: enable=C0322
181 QtCore.QObject.connect(button, QtCore.SIGNAL('clicked()'), cb)194 button.clicked.connect(cb)
182 self.ui.folders.setIndexWidget(model_index, button)195 self.ui.folders.setIndexWidget(model_index, button)
183196
184 self.ui.folders.expandAll()197 self.ui.folders.expandAll()
@@ -196,7 +209,7 @@
196 logger.warning('on_folders_itemActivated: stored path %r '209 logger.warning('on_folders_itemActivated: stored path %r '
197 'does not exist.', volume_path)210 'does not exist.', volume_path)
198 else:211 else:
199 uri = FILE_URI_PREFIX + volume_path212 uri = unicode(QtCore.QUrl.fromLocalFile(volume_path).toString())
200 uri_hook(uri)213 uri_hook(uri)
201214
202 @defer.inlineCallbacks215 @defer.inlineCallbacks
@@ -230,6 +243,7 @@
230 # user accepted, merge the folder content243 # user accepted, merge the folder content
231 yield self.backend.change_volume_settings(volume_id,244 yield self.backend.change_volume_settings(volume_id,
232 {'subscribed': subscribed})245 {'subscribed': subscribed})
246 self.load()
233 else:247 else:
234 # restore old value248 # restore old value
235 old = UNCHECKED if subscribed else CHECKED249 old = UNCHECKED if subscribed else CHECKED
236250
=== modified file 'ubuntuone/controlpanel/gui/qt/gotoweb.py'
--- ubuntuone/controlpanel/gui/qt/gotoweb.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/gotoweb.py 2011-09-26 18:38:27 +0000
@@ -20,10 +20,13 @@
2020
21from PyQt4 import QtGui, QtCore21from PyQt4 import QtGui, QtCore
2222
23from ubuntuone.controlpanel.gui import qt23from twisted.internet import defer
2424
2525from ubuntuone.controlpanel import cache
26class GoToWebButton(QtGui.QPushButton):26from ubuntuone.controlpanel.gui import qt, sign_url, UBUNTUONE_LINK
27
28
29class GoToWebButton(cache.Cache, QtGui.QPushButton):
27 """The GoToWebButton widget"""30 """The GoToWebButton widget"""
2831
29 def __init__(self, *args, **kwargs):32 def __init__(self, *args, **kwargs):
@@ -33,9 +36,20 @@
33 self.setIcon(qt.icon_from_name('external_icon_white'))36 self.setIcon(qt.icon_from_name('external_icon_white'))
34 self.setLayoutDirection(QtCore.Qt.RightToLeft)37 self.setLayoutDirection(QtCore.Qt.RightToLeft)
35 self.clicked.connect(self.on_clicked)38 self.clicked.connect(self.on_clicked)
39 self.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
3640
41 @defer.inlineCallbacks
37 @QtCore.pyqtSlot()42 @QtCore.pyqtSlot()
38 def on_clicked(self):43 def on_clicked(self):
39 """Open self.uri if not None, do nothing otherwise."""44 """Open self.uri if not None, do nothing otherwise."""
40 if self.uri is not None:45 if self.uri is not None:
41 qt.uri_hook(self.uri)46
47 credentials = None
48 if self.uri.startswith(UBUNTUONE_LINK):
49 credentials = yield self.backend.get_credentials()
50
51 uri = self.uri
52 if credentials:
53 uri = sign_url(uri, credentials)
54
55 qt.uri_hook(uri)
4256
=== modified file 'ubuntuone/controlpanel/gui/qt/gui.py'
--- ubuntuone/controlpanel/gui/qt/gui.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/gui.py 2011-09-26 18:38:27 +0000
@@ -21,22 +21,24 @@
2121
22from PyQt4 import QtGui22from PyQt4 import QtGui
2323
24from ubuntuone.controlpanel.logger import setup_logging24from ubuntuone.controlpanel.gui.qt.systray import TrayIcon
25from ubuntuone.controlpanel.gui.qt.ui import mainwindow_ui25from ubuntuone.controlpanel.gui.qt.ui import mainwindow_ui
2626
2727
28logger = setup_logging('qt.gui')
29
30
31class MainWindow(QtGui.QMainWindow):28class MainWindow(QtGui.QMainWindow):
32 """The Main Window of the Control Panel."""29 """The Main Window of the Control Panel."""
3330
34 def __init__(self, close_callback=None):31 def __init__(self, close_callback=None):
35 """Initialize this instance with the UI layout."""32 """Initialize this instance with the UI layout."""
36 QtGui.QMainWindow.__init__(self)33 super(MainWindow, self).__init__()
37 self.ui = mainwindow_ui.Ui_MainWindow()34 self.ui = mainwindow_ui.Ui_MainWindow()
38 self.ui.setupUi(self)35 self.ui.setupUi(self)
39 self.close_callback = close_callback36 self.close_callback = close_callback
37 self._setup()
38
39 def _setup(self):
40 """Do some extra setupping for the UI."""
41 self.ui.control_panel.ui.signin.signinCanceled.connect(self.close)
4042
41 # Invalid name "closeEvent"43 # Invalid name "closeEvent"
42 # pylint: disable=C010344 # pylint: disable=C0103
@@ -46,3 +48,24 @@
46 if self.close_callback is not None:48 if self.close_callback is not None:
47 self.close_callback()49 self.close_callback()
48 event.accept()50 event.accept()
51
52 # pylint: enable=C0103
53
54
55def start(stop, minimized=False, with_icon=False):
56 """Show the UI elements."""
57 # pylint: disable=W0404, F0401
58 if not minimized:
59 if with_icon or minimized:
60 window = MainWindow()
61 else:
62 window = MainWindow(close_callback=stop)
63 window.show()
64 else:
65 window = None
66 if with_icon or minimized:
67 QtGui.QApplication.instance().setQuitOnLastWindowClosed(False)
68 icon = TrayIcon(window=window)
69 else:
70 icon = None
71 return icon, window
4972
=== modified file 'ubuntuone/controlpanel/gui/qt/loadingoverlay.py'
--- ubuntuone/controlpanel/gui/qt/loadingoverlay.py 2011-08-12 19:12:08 +0000
+++ ubuntuone/controlpanel/gui/qt/loadingoverlay.py 2011-09-26 18:38:27 +0000
@@ -18,8 +18,7 @@
1818
19"""Loading animation over a widget."""19"""Loading animation over a widget."""
2020
21from PyQt4 import QtGui21from PyQt4 import QtGui, QtCore
22from PyQt4 import QtCore
2322
24from ubuntuone.controlpanel.gui.qt.ui import loadingoverlay_ui23from ubuntuone.controlpanel.gui.qt.ui import loadingoverlay_ui
2524
@@ -29,12 +28,15 @@
2928
30 In order to have this working, the Widget which is going to use this29 In order to have this working, the Widget which is going to use this
31 overlay has to reimplement the resizeEvent as follows:30 overlay has to reimplement the resizeEvent as follows:
31
32 def resizeEvent(self, event):32 def resizeEvent(self, event):
33 self.overlay.resize(event.size())33 self.overlay.resize(event.size())
34 event.accept()"""34 event.accept()
35
36 """
3537
36 def __init__(self, parent=None):38 def __init__(self, parent=None):
37 QtGui.QFrame.__init__(self, parent)39 super(LoadingOverlay, self).__init__(parent=parent)
38 self.ui = loadingoverlay_ui.Ui_Form()40 self.ui = loadingoverlay_ui.Ui_Form()
39 self.ui.setupUi(self)41 self.ui.setupUi(self)
4042
4143
=== modified file 'ubuntuone/controlpanel/gui/qt/main/linux.py'
--- ubuntuone/controlpanel/gui/qt/main/linux.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/main/linux.py 2011-09-26 18:38:27 +0000
@@ -29,7 +29,7 @@
29# pylint: enable=W061129# pylint: enable=W0611
3030
3131
32def main(switch_to='', alert=False):32def main(switch_to='', alert=False, minimized=False, with_icon=False):
33 """Start the Qt reactor and open the main window."""33 """Start the Qt reactor and open the main window."""
3434
35 # The DBus main loop MUST be initialized before importing the reactor35 # The DBus main loop MUST be initialized before importing the reactor
@@ -49,11 +49,9 @@
49 from qtreactor import qt4reactor49 from qtreactor import qt4reactor
50 qt4reactor.install()50 qt4reactor.install()
51 from twisted.internet import reactor51 from twisted.internet import reactor
52 from ubuntuone.controlpanel.gui.qt.gui import start
5253
53 # pylint believes that reactor has no run nor stop methods. Silence it.
54 # pylint: disable=E110154 # pylint: disable=E1101
55 from ubuntuone.controlpanel.gui.qt.gui import MainWindow55 icon, window = start(reactor.stop,
56 window = MainWindow(close_callback=reactor.stop)56 minimized=minimized, with_icon=with_icon)
57 window.show()
58
59 reactor.run()57 reactor.run()
6058
=== modified file 'ubuntuone/controlpanel/gui/qt/main/windows.py'
--- ubuntuone/controlpanel/gui/qt/main/windows.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/main/windows.py 2011-09-26 18:38:27 +0000
@@ -27,7 +27,7 @@
27# pylint: enable=W061127# pylint: enable=W0611
2828
2929
30def main(switch_to='', alert=False):30def main(switch_to='', alert=False, minimized=False, with_icon=False):
31 """Start the Qt reactor and open the main window."""31 """Start the Qt reactor and open the main window."""
3232
33 # The following cannot be imported outside this function33 # The following cannot be imported outside this function
@@ -35,25 +35,22 @@
35 # pylint: disable=F0401, W040435 # pylint: disable=F0401, W0404
36 import qtreactor.qt4reactor36 import qtreactor.qt4reactor
37 qtreactor.qt4reactor.install()37 qtreactor.qt4reactor.install()
38 from twisted.internet import reactor
39 from ubuntuone.controlpanel.gui.qt.gui import start
3840
39 # The main loop MUST be initialized before importing the reactor41 # The main loop MUST be initialized before importing the reactor
40 # pylint: disable=W061242 # pylint: disable=W0612
41 app = Qt.QApplication(sys.argv)43 app = Qt.QApplication(sys.argv)
44 # Apply font to the entire application
45 QtGui.QFontDatabase.addApplicationFont(':/Ubuntu-R.ttf')
46 QtGui.QFontDatabase.addApplicationFont(':/Ubuntu-B.ttf')
42 # Apply Style Sheet47 # Apply Style Sheet
43 qss_file = QtCore.QFile(":/ubuntuone.qss")48 qss_file = QtCore.QFile(":/ubuntuone.qss")
44 qss_file.open(QtCore.QFile.ReadOnly)49 qss_file.open(QtCore.QFile.ReadOnly)
45 stylesheet = QtCore.QLatin1String(qss_file.readAll())50 stylesheet = QtCore.QLatin1String(qss_file.readAll())
46 app.setStyleSheet(stylesheet)51 app.setStyleSheet(stylesheet)
4752
48 # Apply font to the entire application53 icon, window = start(reactor.stop,
49 QtGui.QFontDatabase.addApplicationFont(':/Ubuntu-R.ttf')54 minimized=minimized, with_icon=with_icon)
50
51 # pylint: disable=W0404, F0401
52 from twisted.internet import reactor
53
54 from ubuntuone.controlpanel.gui.qt.gui import MainWindow
55 window = MainWindow(close_callback=reactor.stop)
56 window.show()
57
58 # pylint: disable=E110155 # pylint: disable=E1101
59 reactor.run()56 reactor.run()
6057
=== modified file 'ubuntuone/controlpanel/gui/qt/preferences.py'
--- ubuntuone/controlpanel/gui/qt/preferences.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/preferences.py 2011-09-26 18:38:27 +0000
@@ -62,7 +62,9 @@
62 """The Preferences Tab Panel widget"""62 """The Preferences Tab Panel widget"""
6363
64 ui_class = preferences_ui64 ui_class = preferences_ui
65 logger = logger
6566
67 # pylint: disable=E0202
66 @defer.inlineCallbacks68 @defer.inlineCallbacks
67 def load(self):69 def load(self):
68 """Load info."""70 """Load info."""
6971
=== added file 'ubuntuone/controlpanel/gui/qt/signin.py'
--- ubuntuone/controlpanel/gui/qt/signin.py 1970-01-01 00:00:00 +0000
+++ ubuntuone/controlpanel/gui/qt/signin.py 2011-09-26 18:38:27 +0000
@@ -0,0 +1,89 @@
1# -*- coding: utf-8 -*-
2
3# Authors: Natalia B Bidart <natalia.bidart@canonical.com>
4#
5# Copyright 2011 Canonical Ltd.
6#
7# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranties of
13# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14# PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program. If not, see <http://www.gnu.org/licenses/>.
18
19"""The signin page."""
20
21from PyQt4 import QtCore
22from twisted.internet import defer
23
24from ubuntuone.controlpanel.gui import RESET_PASSWORD_LINK
25from ubuntuone.controlpanel.gui.qt import icon_from_name, handle_errors
26from ubuntuone.controlpanel.gui.qt.ubuntuonebin import UbuntuOneBin
27from ubuntuone.controlpanel.gui.qt.ui import signin_ui
28from ubuntuone.controlpanel.logger import setup_logging, log_call
29
30
31logger = setup_logging('qt.signin')
32
33
34class SignInPanel(UbuntuOneBin):
35 """The widget for signing in."""
36
37 ui_class = signin_ui
38 logger = logger
39
40 signinCanceled = QtCore.pyqtSignal()
41 credentialsFound = QtCore.pyqtSignal(dict)
42
43 def _setup(self):
44 """Do some extra setupping for the UI."""
45 super(SignInPanel, self)._setup()
46
47 self.ui.forgot_password_button.uri = RESET_PASSWORD_LINK
48 icon = icon_from_name('external_icon_orange')
49 self.ui.forgot_password_button.setIcon(icon)
50
51 self.ui.signin_button.setEnabled(False)
52 for entry in (self.ui.email_entry, self.ui.password_entry):
53 entry.textChanged.connect(self.validate)
54 entry.returnPressed.connect(self.ui.signin_button.click)
55
56 def validate(self, *a, **kw):
57 """Enable sign in button only if email and password are non empty."""
58 email = unicode(self.ui.email_entry.text())
59 password = unicode(self.ui.password_entry.text())
60 self.ui.signin_button.setEnabled(bool(email and password))
61 self.ui.signin_button.style().unpolish(self.ui.signin_button)
62 self.ui.signin_button.style().polish(self.ui.signin_button)
63
64 # pylint: disable=E0202
65 @defer.inlineCallbacks
66 def load(self):
67 """Load specific tab info."""
68 yield self.backend.get_credentials()
69
70 @QtCore.pyqtSlot()
71 @handle_errors(logger=logger)
72 @log_call(logger.debug)
73 @defer.inlineCallbacks
74 def on_signin_button_clicked(self):
75 """The 'Sign in' button was clicked."""
76 email = unicode(self.ui.email_entry.text())
77 password = unicode(self.ui.password_entry.text())
78 self.is_processing = True
79 try:
80 result = yield self.backend.login(email=email, password=password)
81 logger.info('Emitting credentialsFound for email %r.', email)
82 self.credentialsFound.emit(result)
83 finally:
84 self.is_processing = False
85
86 @QtCore.pyqtSlot()
87 def on_cancel_button_clicked(self):
88 """The 'Cancel' button was clicked."""
89 self.signinCanceled.emit()
090
=== added file 'ubuntuone/controlpanel/gui/qt/systray.py'
--- ubuntuone/controlpanel/gui/qt/systray.py 1970-01-01 00:00:00 +0000
+++ ubuntuone/controlpanel/gui/qt/systray.py 2011-09-26 18:38:27 +0000
@@ -0,0 +1,68 @@
1# -*- coding: utf-8 -*-
2
3# Authors: Roberto Alsina <roberto.alsina@canonical.com>
4#
5# Copyright 2011 Canonical Ltd.
6#
7# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranties of
13# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14# PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program. If not, see <http://www.gnu.org/licenses/>.
18"""System notification area icon."""
19
20from PyQt4 import QtGui
21
22
23class TrayIcon(QtGui.QSystemTrayIcon):
24
25 """System notification icon."""
26
27 def __init__(self, window=None):
28 super(TrayIcon, self).__init__(None)
29 self.setIcon(QtGui.QIcon(":/u1icon.png"))
30 self.setVisible(True)
31 self.window = window
32 self.activated.connect(self.on_activated)
33 self.context_menu = QtGui.QMenu()
34 self.restore = QtGui.QAction("Restore", self,
35 triggered=self.restore_window)
36 self.quit = QtGui.QAction("Quit Ubuntu One", self,
37 triggered=self.stop)
38 self.context_menu.addAction(self.restore)
39 self.context_menu.addSeparator()
40 self.context_menu.addAction(self.quit)
41 self.setContextMenu(self.context_menu)
42
43 def on_activated(self, reason):
44 """The user activated the icon."""
45 if reason == self.Trigger: # Left-click
46 self.restore_window()
47
48 def restore_window(self):
49 """Show the main window."""
50 if self.window is None:
51 # pylint: disable=W0404
52 from ubuntuone.controlpanel.gui.qt.gui import MainWindow
53 # pylint: enable=W0404
54 self.window = MainWindow(close_callback=self.delete_window)
55 self.window.show()
56
57 def delete_window(self):
58 """Close and remove the main window."""
59 if self.window is not None:
60 self.window.close()
61 self.window = None
62
63 def stop(self):
64 """Stop the application."""
65 # pylint: disable=W0404
66 from twisted.internet import reactor
67 # pylint: enable=W0404
68 reactor.stop()
069
=== modified file 'ubuntuone/controlpanel/gui/qt/tests/__init__.py'
--- ubuntuone/controlpanel/gui/qt/tests/__init__.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/tests/__init__.py 2011-09-26 18:38:27 +0000
@@ -18,12 +18,16 @@
1818
19"""The test suite for the Qt UI for the control panel for Ubuntu One."""19"""The test suite for the Qt UI for the control panel for Ubuntu One."""
2020
21import logging
21import os22import os
2223import urllib
23from PyQt4 import QtCore24
2425from PyQt4 import QtGui, QtCore
25from ubuntuone.controlpanel import backend26from ubuntuone.devtools.handlers import MementoHandler
26from ubuntuone.controlpanel.tests import TestCase, EXPECTED_ACCOUNT_INFO27
28from ubuntuone.controlpanel import backend, cache
29from ubuntuone.controlpanel.tests import TestCase, EXPECTED_ACCOUNT_INFO, TOKEN
30from ubuntuone.controlpanel.gui import qt, UBUNTUONE_FROM_OAUTH
27from ubuntuone.controlpanel.gui.tests import FakedObject, USER_HOME31from ubuntuone.controlpanel.gui.tests import FakedObject, USER_HOME
2832
29# Attribute 'yyy' defined outside __init__, access to a protected member33# Attribute 'yyy' defined outside __init__, access to a protected member
@@ -76,21 +80,6 @@
76 return folder80 return folder
7781
7882
79def skip_if_abstract_class(test):
80 """Decorator to skip a test if is an abstract class."""
81
82 def inner(instance):
83 """Skip a test if is an abstract class."""
84 abstract = instance.class_ui is None
85 result = None
86 if not abstract:
87 result = test(instance)
88
89 return result
90
91 return inner
92
93
94class FakeUi(FakedObject):83class FakeUi(FakedObject):
95 """A fake Ui object."""84 """A fake Ui object."""
9685
@@ -114,7 +103,7 @@
114 backend.UPLOAD_KEY: -1, # no limit103 backend.UPLOAD_KEY: -1, # no limit
115 }104 }
116105
117 next_result = object()106 next_result = []
118 exposed_methods = [107 exposed_methods = [
119 'account_info', # account108 'account_info', # account
120 'devices_info', 'device_names_info', # devices109 'devices_info', 'device_names_info', # devices
@@ -128,13 +117,41 @@
128 'file_sync_settings_info',117 'file_sync_settings_info',
129 'change_file_sync_settings',118 'change_file_sync_settings',
130 'restore_file_sync_settings',119 'restore_file_sync_settings',
131 'shutdown',120 'shutdown', 'login',
132 ]121 ]
133122
134123 def get_credentials(self):
135class FakedConfirmDialog(object):124 """Fake credentials retrieval."""
125 self._called['get_credentials'] = ((), {})
126 return TOKEN
127
128
129class CrashyBackendException(Exception):
130 """A faked backend crash."""
131
132
133class CrashyBackend(FakedControlPanelBackend):
134 """A faked backend that crashes."""
135
136 def __init__(self, *args, **kwargs):
137 super(CrashyBackend, self).__init__(*args, **kwargs)
138 for i in self.exposed_methods + ['get_credentials']:
139 setattr(self, i, self._fail(i))
140
141 def _fail(self, f):
142 """Crash boom bang."""
143
144 def inner(*args, **kwargs):
145 """Raise a custom exception."""
146 raise CrashyBackendException(f)
147
148 return inner
149
150
151class FakedDialog(object):
136 """Fake a confirmation dialog."""152 """Fake a confirmation dialog."""
137153
154 Close = 0
138 response = args = kwargs = None155 response = args = kwargs = None
139156
140 @classmethod157 @classmethod
@@ -149,6 +166,7 @@
149 """Fake a file chooser dialog."""166 """Fake a file chooser dialog."""
150167
151 response = args = kwargs = None168 response = args = kwargs = None
169 DontUseNativeDialog = 4
152170
153 # Invalid name "getExistingDirectory"171 # Invalid name "getExistingDirectory"
154 # pylint: disable=C0103172 # pylint: disable=C0103
@@ -168,19 +186,43 @@
168 innerclass_name = None186 innerclass_name = None
169 class_ui = None187 class_ui = None
170 kwargs = {}188 kwargs = {}
189 logger = None
171190
172 @skip_if_abstract_class
173 def setUp(self):191 def setUp(self):
192 cache.Cache._shared_objects = {}
174 super(BaseTestCase, self).setUp()193 super(BaseTestCase, self).setUp()
175 self.patch(backend, 'ControlBackend', FakedControlPanelBackend)194 self.patch(backend, 'ControlBackend', FakedControlPanelBackend)
176 # self.class_ui is not callable195
177 # pylint: disable=E1102196 self.ui = None
178 self.ui = self.class_ui(**self.kwargs)197 if self.class_ui is not None:
179 self.addCleanup(self.ui.destroy)198 # self.class_ui is not callable
180199 # pylint: disable=E1102
181 if hasattr(self.ui, 'backend'):200 self.ui = self.class_ui(**self.kwargs)
182 # clean backend calls201 # pylint: enable=E1102
183 self.ui.backend._called.clear()202 self.addCleanup(self.ui.destroy)
203
204 if getattr(self.ui, 'backend', None) is not None:
205 self.addCleanup(self.ui.backend._called.clear)
206
207 logger = self.logger if self.logger is not None else \
208 getattr(self.ui, 'logger', None)
209 self.memento = None
210 if logger is not None:
211 self.memento = MementoHandler()
212 self.memento.setLevel(logging.DEBUG)
213 logger.addHandler(self.memento)
214 self.addCleanup(logger.removeHandler, self.memento)
215
216 # default response if user does nothing
217 FakedFileDialog.response = QtCore.QString('')
218 FakedFileDialog.args = None
219 FakedFileDialog.kwargs = None
220 self.patch(QtGui, 'QFileDialog', FakedFileDialog)
221
222 FakedDialog.response = None
223 FakedDialog.args = None
224 FakedDialog.kwargs = None
225 self.patch(QtGui, 'QMessageBox', FakedDialog)
184226
185 def get_pixmap_data(self, pixmap):227 def get_pixmap_data(self, pixmap):
186 """Get the raw data of a QPixmap."""228 """Get the raw data of a QPixmap."""
@@ -202,6 +244,19 @@
202 self.assertIn(method_name, self.ui.backend._called)244 self.assertIn(method_name, self.ui.backend._called)
203 self.assertEqual(self.ui.backend._called[method_name], (args, kwargs))245 self.assertEqual(self.ui.backend._called[method_name], (args, kwargs))
204246
247 def assert_uri_hook_called(self, button, url):
248 """Check that uri_hook was called with 'url' when clicking 'button'."""
249 self.patch(qt, 'uri_hook', self._set_called)
250 button.click()
251
252 self.assertEqual(len(self._called), 2, 'uri_hook must be called.')
253 self.assertEqual(len(self._called[0]), 1, 'uri_hook must be called.')
254 actual_url = self._called[0][0]
255 if actual_url.startswith(UBUNTUONE_FROM_OAUTH):
256 self.assertIn(urllib.urlencode({'next': url}), actual_url)
257 else:
258 self.assertEqual(actual_url, url)
259
205 def test_init_loads_ui(self, expected_setup_ui=None):260 def test_init_loads_ui(self, expected_setup_ui=None):
206 """The __init__ method loads the ui."""261 """The __init__ method loads the ui."""
207 if self.innerclass_ui is None:262 if self.innerclass_ui is None:
@@ -219,3 +274,8 @@
219 expected_setup_ui = expected_setup_ui(self.ui)274 expected_setup_ui = expected_setup_ui(self.ui)
220 self.assertEqual(self.ui.ui._called,275 self.assertEqual(self.ui.ui._called,
221 {'setupUi': ((expected_setup_ui,), {})})276 {'setupUi': ((expected_setup_ui,), {})})
277
278 def test_backend_is_correct(self):
279 """The backend instance is correct."""
280 if getattr(self.ui, 'backend', None) is not None:
281 self.assertIsInstance(self.ui.backend, FakedControlPanelBackend)
222282
=== modified file 'ubuntuone/controlpanel/gui/qt/tests/test_account.py'
--- ubuntuone/controlpanel/gui/qt/tests/test_account.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/tests/test_account.py 2011-09-26 18:38:27 +0000
@@ -20,7 +20,6 @@
2020
21from twisted.internet import defer21from twisted.internet import defer
2222
23from ubuntuone.controlpanel.gui import qt
24from ubuntuone.controlpanel.gui.qt import account as gui23from ubuntuone.controlpanel.gui.qt import account as gui
25from ubuntuone.controlpanel.gui.qt.tests import (24from ubuntuone.controlpanel.gui.qt.tests import (
26 SAMPLE_ACCOUNT_INFO, SAMPLE_EMAIL, SAMPLE_NAME, SAMPLE_PLAN,25 SAMPLE_ACCOUNT_INFO, SAMPLE_EMAIL, SAMPLE_NAME, SAMPLE_PLAN,
@@ -75,14 +74,10 @@
7574
76 def test_edit_account_button(self):75 def test_edit_account_button(self):
77 """When clicking the edit account button, the proper url is opened."""76 """When clicking the edit account button, the proper url is opened."""
78 self.patch(qt, 'uri_hook', self._set_called)77 self.assert_uri_hook_called(self.ui.ui.edit_profile_button,
79 self.ui.ui.edit_profile_button.click()78 gui.EDIT_PROFILE_LINK)
80
81 self.assertEqual(self._called, ((gui.EDIT_PROFILE_LINK,), {}))
8279
83 def test_edit_services_button(self):80 def test_edit_services_button(self):
84 """When clicking the mobile plan button, the proper url is opened."""81 """When clicking the mobile plan button, the proper url is opened."""
85 self.patch(qt, 'uri_hook', self._set_called)82 self.assert_uri_hook_called(self.ui.ui.edit_services_button,
86 self.ui.ui.edit_services_button.click()83 gui.EDIT_ACCOUNT_LINK)
87
88 self.assertEqual(self._called, ((gui.EDIT_ACCOUNT_LINK,), {}))
8984
=== modified file 'ubuntuone/controlpanel/gui/qt/tests/test_addfolder.py'
--- ubuntuone/controlpanel/gui/qt/tests/test_addfolder.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/tests/test_addfolder.py 2011-09-26 18:38:27 +0000
@@ -29,7 +29,9 @@
29from ubuntuone.controlpanel.gui.qt import addfolder as gui29from ubuntuone.controlpanel.gui.qt import addfolder as gui
30from ubuntuone.controlpanel.gui.qt.tests import (30from ubuntuone.controlpanel.gui.qt.tests import (
31 BaseTestCase,31 BaseTestCase,
32 FakedConfirmDialog,32 CrashyBackend,
33 CrashyBackendException,
34 FakedDialog,
33 FakedFileDialog,35 FakedFileDialog,
34 set_path_on_file_dialog,36 set_path_on_file_dialog,
35)37)
@@ -53,20 +55,6 @@
53 os.environ['HOME'] = USER_HOME55 os.environ['HOME'] = USER_HOME
54 self.addCleanup(lambda: os.environ.__setitem__('HOME', old_home))56 self.addCleanup(lambda: os.environ.__setitem__('HOME', old_home))
5557
56 # default response if user does nothing
57 FakedFileDialog.response = gui.QtCore.QString('')
58 FakedFileDialog.args = None
59 FakedFileDialog.kwargs = None
60 self.patch(gui.QtGui, 'QFileDialog', FakedFileDialog)
61
62 FakedConfirmDialog.response = None
63 FakedConfirmDialog.args = None
64 FakedConfirmDialog.kwargs = None
65 self.patch(gui.QtGui, 'QMessageBox', FakedConfirmDialog)
66
67 # reset backend state
68 self.ui.backend._called.clear()
69
70 @defer.inlineCallbacks58 @defer.inlineCallbacks
71 def assert_does_nothing(self, method_call):59 def assert_does_nothing(self, method_call):
72 """Nothing happens.60 """Nothing happens.
@@ -92,7 +80,10 @@
92 yield self.ui.click()80 yield self.ui.click()
9381
94 self.assertEqual(FakedFileDialog.args, ())82 self.assertEqual(FakedFileDialog.args, ())
95 self.assertEqual(FakedFileDialog.kwargs, {'parent': self.ui})83 self.assertEqual(FakedFileDialog.kwargs, {
84 'options': gui.QtGui.QFileDialog.DontUseNativeDialog,
85 'parent': self.ui,
86 })
9687
97 @defer.inlineCallbacks88 @defer.inlineCallbacks
98 def test_does_nothing_if_user_closes_file_chooser(self):89 def test_does_nothing_if_user_closes_file_chooser(self):
@@ -100,8 +91,8 @@
100 yield self.assert_does_nothing(self.ui.click)91 yield self.assert_does_nothing(self.ui.click)
10192
102 # the warning dialog was not opened93 # the warning dialog was not opened
103 self.assertEqual(FakedConfirmDialog.args, None)94 self.assertEqual(FakedDialog.args, None)
104 self.assertEqual(FakedConfirmDialog.kwargs, None)95 self.assertEqual(FakedDialog.kwargs, None)
10596
106 @defer.inlineCallbacks97 @defer.inlineCallbacks
107 def test_opens_warning_if_folder_path_not_valid(self):98 def test_opens_warning_if_folder_path_not_valid(self):
@@ -113,9 +104,9 @@
113104
114 args = {'folder_path': folder_path, 'home_folder': USER_HOME}105 args = {'folder_path': folder_path, 'home_folder': USER_HOME}
115 msg = gui.FOLDER_INVALID_PATH % args106 msg = gui.FOLDER_INVALID_PATH % args
116 self.assertEqual(FakedConfirmDialog.args,107 self.assertEqual(FakedDialog.args,
117 (self.ui, '', msg, gui.CLOSE))108 (self.ui, '', msg, gui.CLOSE))
118 self.assertEqual(FakedConfirmDialog.kwargs, {})109 self.assertEqual(FakedDialog.kwargs, {})
119110
120 yield self.assert_does_nothing(self.ui.click)111 yield self.assert_does_nothing(self.ui.click)
121112
@@ -126,8 +117,8 @@
126 yield self.ui.click()117 yield self.ui.click()
127118
128 # no warning119 # no warning
129 self.assertEqual(FakedConfirmDialog.args, None)120 self.assertEqual(FakedDialog.args, None)
130 self.assertEqual(FakedConfirmDialog.kwargs, None)121 self.assertEqual(FakedDialog.kwargs, None)
131 # backend called122 # backend called
132 self.assert_backend_called('create_folder', folder_path=folder)123 self.assert_backend_called('create_folder', folder_path=folder)
133124
@@ -138,8 +129,8 @@
138 yield self.ui.click()129 yield self.ui.click()
139130
140 # no warning131 # no warning
141 self.assertEqual(FakedConfirmDialog.args, None)132 self.assertEqual(FakedDialog.args, None)
142 self.assertEqual(FakedConfirmDialog.kwargs, None)133 self.assertEqual(FakedDialog.kwargs, None)
143 # backend called134 # backend called
144 self.assert_backend_called('create_folder', folder_path=folder)135 self.assert_backend_called('create_folder', folder_path=folder)
145136
@@ -167,3 +158,12 @@
167 yield self.ui.click()158 yield self.ui.click()
168159
169 self.assertEqual(self._called, ((), {}))160 self.assertEqual(self._called, ((), {}))
161
162 @defer.inlineCallbacks
163 def test_backend_error_is_handled(self):
164 """Any error from the backend is properly handled."""
165 set_path_on_file_dialog()
166 self.patch(self.ui, 'backend', CrashyBackend())
167 yield self.ui.click()
168
169 self.assertTrue(self.memento.check_exception(CrashyBackendException))
170170
=== added file 'ubuntuone/controlpanel/gui/qt/tests/test_common.py'
--- ubuntuone/controlpanel/gui/qt/tests/test_common.py 1970-01-01 00:00:00 +0000
+++ ubuntuone/controlpanel/gui/qt/tests/test_common.py 2011-09-26 18:38:27 +0000
@@ -0,0 +1,210 @@
1# -*- coding: utf-8 -*-
2
3# Authors: Natalia B Bidart <natalia.bidart@canonical.com>
4#
5# Copyright 2011 Canonical Ltd.
6#
7# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranties of
13# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14# PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program. If not, see <http://www.gnu.org/licenses/>.
18
19"""Tests for the uri_hook helper."""
20
21import logging
22
23from PyQt4 import QtGui, QtCore
24from twisted.internet import defer
25
26from ubuntuone.controlpanel.logger import setup_logging
27from ubuntuone.controlpanel.gui.qt import uri_hook, handle_errors
28from ubuntuone.controlpanel.gui.qt.tests import (
29 BaseTestCase,
30 FakedDialog,
31)
32
33
34class UriHookTestCase(BaseTestCase):
35 """The test suite for the uri_hook."""
36
37 @defer.inlineCallbacks
38 def setUp(self):
39 yield super(UriHookTestCase, self).setUp()
40 self.patch(QtGui.QDesktopServices, 'openUrl', self._set_called)
41
42 def test_opens_url(self):
43 """The url is opened properly."""
44 expected = 'foo bar'
45 uri_hook(expected)
46 self.assertEqual(self._called, ((QtCore.QUrl(expected),), {}))
47
48 def test_opens_url_encoded(self):
49 """The encoded url is opened properly."""
50 expected = 'http://foo.bar/?next=https://one.ubuntu.com/'
51 uri_hook(expected)
52 self.assertEqual(self._called, ((QtCore.QUrl(expected),), {}))
53
54
55class HandleErrorTestCase(BaseTestCase):
56 """Test suite for the generic error handler."""
57
58 error_handler = None
59 use_logger = False
60 logger = logging.getLogger() # root logger
61
62 @defer.inlineCallbacks
63 def setUp(self):
64 yield super(HandleErrorTestCase, self).setUp()
65 self.called = None
66 self.result = None
67 self.failure = None
68 self.error_handler_called = None
69
70 if self.use_logger:
71 logger = self.logger
72 else:
73 logger = None
74
75 self.decorate_me = handle_errors(error_handler=self.error_handler,
76 logger=logger)(self._decorate_me)
77
78 @defer.inlineCallbacks
79 def _decorate_me(self, *args, **kwargs):
80 """Helper to test thye decorator."""
81 if self.failure:
82 # Raising only classes, instances or string are allowed
83 # pylint: disable=E0702
84 raise self.failure
85
86 yield
87 self.called = (args, kwargs)
88 defer.returnValue(self.result)
89
90 @defer.inlineCallbacks
91 def test_is_decorator(self):
92 """Is a decorator."""
93 yield self.decorate_me()
94
95 @defer.inlineCallbacks
96 def test_params_are_passed(self):
97 """Named and unnamed arguments are passed."""
98 args = ({}, object(), 'foo')
99 kwargs = {'1': 1, 'test': None, '0': ['a']}
100 yield self.decorate_me(*args, **kwargs)
101
102 self.assertTrue(self.called, (args, kwargs))
103
104 @defer.inlineCallbacks
105 def test_result_is_returned(self):
106 """Result is returned."""
107 self.result = object()
108 result = yield self.decorate_me()
109
110 self.assertEqual(self.result, result)
111
112 def test_name_is_preserved(self):
113 """The method name is not masqueraded."""
114 self.assertEqual(self.decorate_me.__name__, self._decorate_me.__name__)
115
116 @defer.inlineCallbacks
117 def test_exeptions_are_handled(self):
118 """Any exception is handled and logged in the root logger."""
119 msg = 'This is me failing badly.'
120 self.failure = Exception(msg)
121
122 yield self.decorate_me()
123
124 logged = self.memento.check_exception(self.failure.__class__, msg)
125 recs = '\n'.join(rec.exc_text for rec in self.memento.records)
126 self.assertTrue(logged, 'Exception must be logged, got:\n%s' % recs)
127
128 @defer.inlineCallbacks
129 def test_show_error_message(self):
130 """On error, show an error message."""
131 self.failure = Exception()
132
133 yield self.decorate_me()
134
135 msg = self.failure.__class__.__name__
136 self.assertEqual(FakedDialog.args,
137 (None, '', msg, QtGui.QMessageBox.Close))
138 self.assertEqual(FakedDialog.kwargs, {})
139
140 @defer.inlineCallbacks
141 def test_show_error_message_if_args(self):
142 """On error, show an error message."""
143 msg1 = 'This is me failing badly.'
144 msg2 = 'More details about what went wrong.'
145 obj = object()
146 self.failure = Exception(msg1, msg2, obj)
147
148 yield self.decorate_me()
149
150 msg = '\n'.join(map(repr, (msg1, msg2, obj)))
151 msg = self.failure.__class__.__name__ + '\n' + msg
152 self.assertEqual(FakedDialog.args,
153 (None, '', msg, QtGui.QMessageBox.Close))
154 self.assertEqual(FakedDialog.kwargs, {})
155
156 @defer.inlineCallbacks
157 def test_show_error_message_if_mapping(self):
158 """On error, show an error message."""
159 msg1 = 'This is me failing badly.'
160 msg2 = 'More details about what went wrong.'
161 errdict = {'foo': msg1, 'bar': msg2}
162 self.failure = Exception(errdict)
163
164 yield self.decorate_me()
165
166 msg = '\n'.join((msg1, msg2))
167 self.assertEqual(FakedDialog.args,
168 (None, '', msg, QtGui.QMessageBox.Close))
169 self.assertEqual(FakedDialog.kwargs, {})
170
171 @defer.inlineCallbacks
172 def test_no_error_message_if_no_exception(self):
173 """On success, do not show an error message."""
174 yield self.decorate_me()
175
176 self.assertEqual(FakedDialog.args, None)
177 self.assertEqual(FakedDialog.kwargs, None)
178
179 @defer.inlineCallbacks
180 def test_call_error_handler(self):
181 """On success, do not execute error_handler."""
182 yield self.decorate_me()
183 self.assertFalse(self.error_handler_called)
184
185
186class HandleErrorWithCustomLoggerTestCase(HandleErrorTestCase):
187 """Test suite for the generic error handler."""
188
189 use_logger = True
190 logger = setup_logging('HandleErrorWithoutLoggerTestCase') # custom logger
191
192
193class HandleErrorWithHandlerTestCase(HandleErrorTestCase):
194 """Test suite for the generic error handler when using a custom handler."""
195
196 @defer.inlineCallbacks
197 def error_handler(self, *a, **kw):
198 """Implement an error handler."""
199 self.error_handler_called = (a, kw)
200 yield
201
202 @defer.inlineCallbacks
203 def test_call_error_handler(self):
204 """On error, execute error_handler."""
205 msg = 'This is me failing badly.'
206 self.failure = Exception(msg)
207
208 yield self.decorate_me()
209
210 self.assertEqual(self.error_handler_called, ((), {}))
0211
=== modified file 'ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py'
--- ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py 2011-09-26 18:38:27 +0000
@@ -22,14 +22,16 @@
2222
23from twisted.internet import defer23from twisted.internet import defer
2424
25from ubuntuone.controlpanel.gui import qt
26from ubuntuone.controlpanel.gui.qt import controlpanel as gui25from ubuntuone.controlpanel.gui.qt import controlpanel as gui
27from ubuntuone.controlpanel.gui.qt.tests import (26from ubuntuone.controlpanel.gui.qt.tests import (
28 BaseTestCase, SAMPLE_ACCOUNT_INFO, SAMPLE_NAME,27 SAMPLE_ACCOUNT_INFO, SAMPLE_NAME, TOKEN,
29)28)
3029from ubuntuone.controlpanel.gui.qt.tests.test_ubuntuonebin import (
3130 UbuntuOneBinTestCase,
32class ControlPanelTestCase(BaseTestCase):31)
32
33
34class ControlPanelTestCase(UbuntuOneBinTestCase):
33 """Test the qt control panel."""35 """Test the qt control panel."""
3436
35 innerclass_ui = gui.controlpanel_ui37 innerclass_ui = gui.controlpanel_ui
@@ -39,18 +41,68 @@
39 @defer.inlineCallbacks41 @defer.inlineCallbacks
40 def setUp(self):42 def setUp(self):
41 yield super(ControlPanelTestCase, self).setUp()43 yield super(ControlPanelTestCase, self).setUp()
44 self.patch(self.ui.ui.folders_tab, 'process_info', lambda info: None)
42 self.ui.backend.next_result = SAMPLE_ACCOUNT_INFO45 self.ui.backend.next_result = SAMPLE_ACCOUNT_INFO
4346
44 def test_backend(self):47 @defer.inlineCallbacks
45 """Backend is created."""48 def test_is_processing_while_asking_info(self):
46 self.assertIsInstance(self.ui.backend,49 """The ui is processing while the contents are loaded."""
47 gui.backend.ControlBackend)50 def check():
51 """The ui must be is_processing."""
52 self.assertTrue(self.ui.is_processing, 'ui must be processing')
53 return {}
54
55 self.patch(self.ui.backend, 'get_credentials', check)
56
57 yield self.ui.load() # trigger the info request
58 self.assertFalse(self.ui.is_processing, 'ui must not be processing')
59
60 @defer.inlineCallbacks
61 def test_credentials_are_requested_on_load(self):
62 """The info is requested to the backend."""
63 yield self.ui.load()
64 self.assert_backend_called('get_credentials')
65
66 @defer.inlineCallbacks
67 def test_on_credentials_not_found_called(self):
68 """If no credentials, on_credentials_not_found is called."""
69 self.patch(self.ui, 'on_credentials_not_found', self._set_called)
70 self.patch(self.ui.backend, 'get_credentials', lambda: {})
71 yield self.ui.load()
72
73 self.assertEqual(self._called, ((), {}))
74
75 def test_on_credentials_not_found(self):
76 """The signin panel is shown."""
77 self.ui.on_credentials_found()
78 self.ui.on_credentials_not_found()
79 self.assertIs(self.ui.ui.switcher.currentWidget(), self.ui.ui.signin)
80
81 @defer.inlineCallbacks
82 def test_on_credentials_found_called(self):
83 """If credentials, on_credentials_not_found is called."""
84 self.patch(self.ui, 'on_credentials_found', self._set_called)
85 yield self.ui.load()
86
87 self.assertEqual(self._called, ((), {}))
88
89 def test_on_credentials_found(self):
90 """The management panel is shown."""
91 self.patch(self.ui, 'connect_file_sync', self._set_called)
92 self.ui.on_credentials_not_found()
93 self.ui.on_credentials_found()
94
95 self.assertIs(self.ui.ui.switcher.currentWidget(),
96 self.ui.ui.management)
97 self.assertEqual(self._called, ((), {}))
4898
49 @defer.inlineCallbacks99 @defer.inlineCallbacks
50 def test_info_is_requested_on_load(self):100 def test_info_is_requested_on_load(self):
51 """The info is requested to the backend."""101 """The info is requested to the backend."""
102 self.patch(self.ui, 'process_info', self._set_called)
52 yield self.ui.load()103 yield self.ui.load()
53 self.assert_backend_called('account_info')104 self.assert_backend_called('account_info')
105 self.assertEqual(self._called, ((SAMPLE_ACCOUNT_INFO,), {}))
54106
55 def test_process_info(self):107 def test_process_info(self):
56 """The info is processed when ready."""108 """The info is processed when ready."""
@@ -72,32 +124,85 @@
72 msg = gui.PERCENTAGE_LABEL % percentage_usage124 msg = gui.PERCENTAGE_LABEL % percentage_usage
73 self.assertEqual(self.ui.ui.percentage_usage_label.text(), msg)125 self.assertEqual(self.ui.ui.percentage_usage_label.text(), msg)
74126
127 def test_update_over_quota(self):
128 """Check the labels state when the user exceed the quota."""
129 percentage_value = 100
130 # pylint: disable=W0212
131 self.ui._update_quota({'percentage': percentage_value})
132 # pylint: enable=W0212
133
134 self.assertTrue(
135 self.ui.ui.percentage_usage_label.property("OverQuota").toBool())
136 self.assertTrue(
137 self.ui.ui.quota_usage_label.property("OverQuota").toBool())
138
139 def test_update_quota_in_range(self):
140 """Check the labels state when the quota is under the threshold."""
141 percentage_value = 50
142 # pylint: disable=W0212
143 self.ui._update_quota({'percentage': percentage_value})
144 # pylint: enable=W0212
145
146 self.assertFalse(
147 self.ui.ui.percentage_usage_label.property("OverQuota").toBool())
148 self.assertFalse(
149 self.ui.ui.quota_usage_label.property("OverQuota").toBool())
150
151 def test_on_local_device_removed(self):
152 """On DeviesPanel's localDeviceRemoved, emit credentialsNotFound."""
153 self.ui.ui.devices_tab.localDeviceRemoved.emit()
154 self.assertIs(self.ui.ui.switcher.currentWidget(), self.ui.ui.signin)
155
156 def test_on_signin_credentials_found(self):
157 """On SignInPanel's credentialsFound, the management panel is shown."""
158 self.patch(self.ui, 'load', self._set_called)
159 self.ui.ui.signin.credentialsFound.emit(TOKEN)
160
161 self.assertEqual(self._called, ((), {}))
162
163 @defer.inlineCallbacks
164 def test_connect_file_sync_with_autoconnect(self):
165 """Connect is called if autoconnect is enabled."""
166 settings = {gui.AUTOCONNECT_KEY: True}
167 self.patch(self.ui.backend, 'file_sync_settings_info',
168 lambda: defer.succeed(settings))
169
170 yield self.ui.connect_file_sync()
171
172 self.assert_backend_called('connect_files')
173
174 @defer.inlineCallbacks
175 def test_connect_file_sync_without_autoconnect(self):
176 """Connect is called if autoconnect is disabled."""
177 settings = {gui.AUTOCONNECT_KEY: False}
178 self.patch(self.ui.backend, 'file_sync_settings_info',
179 lambda: defer.succeed(settings))
180
181 yield self.ui.connect_file_sync()
182
183 # pylint: disable=W0212
184 self.assertNotIn('connect_files', self.ui.backend._called)
185
75186
76class ExternalLinkButtonsTestCase(ControlPanelTestCase):187class ExternalLinkButtonsTestCase(ControlPanelTestCase):
77 """The link in the go-to-web buttons are correct."""188 """The link in the go-to-web buttons are correct."""
78189
79 @defer.inlineCallbacks
80 def setUp(self):
81 self.patch(qt, 'uri_hook', self._set_called)
82 self.patch(gui, 'uri_hook', self._set_called)
83 yield super(ExternalLinkButtonsTestCase, self).setUp()
84
85 def test_get_more_space_button(self):190 def test_get_more_space_button(self):
86 """When clicking the get more GB button, the proper url is opened."""191 """When clicking the get more GB button, the proper url is opened."""
87 self.ui.ui.get_more_space_button.click()192 self.assert_uri_hook_called(self.ui.ui.get_more_space_button,
88 self.assertEqual(self._called, ((gui.EDIT_ACCOUNT_LINK,), {}))193 gui.EDIT_SERVICES_LINK)
89194
90 def test_help_button(self):195 def test_help_button(self):
91 """When clicking the help button, the proper url is opened."""196 """When clicking the help button, the proper url is opened."""
92 self.ui.ui.help_button.click()197 self.assert_uri_hook_called(self.ui.ui.help_button,
93 self.assertEqual(self._called, ((gui.GET_SUPPORT_LINK,), {}))198 gui.GET_SUPPORT_LINK)
94199
95 def test_twitter_button(self):200 def test_twitter_button(self):
96 """When clicking the twitter button, the proper url is opened."""201 """When clicking the twitter button, the proper url is opened."""
97 self.ui.ui.twitter_button.click()202 self.assert_uri_hook_called(self.ui.ui.twitter_button,
98 self.assertEqual(self._called, ((gui.TWITTER_LINK,), {}))203 gui.TWITTER_LINK)
99204
100 def test_facebook_button(self):205 def test_facebook_button(self):
101 """When clicking the facebook button, the proper url is opened."""206 """When clicking the facebook button, the proper url is opened."""
102 self.ui.ui.facebook_button.click()207 self.assert_uri_hook_called(self.ui.ui.facebook_button,
103 self.assertEqual(self._called, ((gui.FACEBOOK_LINK,), {}))208 gui.FACEBOOK_LINK)
104209
=== modified file 'ubuntuone/controlpanel/gui/qt/tests/test_device.py'
--- ubuntuone/controlpanel/gui/qt/tests/test_device.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/tests/test_device.py 2011-09-26 18:38:27 +0000
@@ -23,8 +23,9 @@
23from ubuntuone.controlpanel.gui.qt import device as gui23from ubuntuone.controlpanel.gui.qt import device as gui
24from ubuntuone.controlpanel.gui.qt.tests import (24from ubuntuone.controlpanel.gui.qt.tests import (
25 BaseTestCase,25 BaseTestCase,
26 FakedConfirmDialog,26 CrashyBackend,
27 FakedControlPanelBackend,27 CrashyBackendException,
28 FakedDialog,
28 SAMPLE_COMPUTER_INFO,29 SAMPLE_COMPUTER_INFO,
29 SAMPLE_PHONE_INFO,30 SAMPLE_PHONE_INFO,
30)31)
@@ -40,18 +41,14 @@
40 innerclass_ui = gui.device_ui41 innerclass_ui = gui.device_ui
41 innerclass_name = "Ui_Form"42 innerclass_name = "Ui_Form"
42 class_ui = gui.DeviceWidget43 class_ui = gui.DeviceWidget
43 backend = FakedControlPanelBackend()
44 device_id = 'zaraza'44 device_id = 'zaraza'
45 kwargs = {'backend': backend, 'device_id': device_id}45 kwargs = {'device_id': device_id}
46 logger = gui.logger
4647
47 def test_has_id(self):48 def test_has_id(self):
48 """The device as an id, None by default."""49 """The device as an id, None by default."""
49 self.assertEqual(self.ui.id, self.device_id)50 self.assertEqual(self.ui.id, self.device_id)
5051
51 def test_has_backend(self):
52 """The device as a backend, None by default."""
53 self.assertIs(self.ui.backend, self.backend)
54
55 def test_update_device_info(self):52 def test_update_device_info(self):
56 """The widget is updated with the info."""53 """The widget is updated with the info."""
57 info = SAMPLE_COMPUTER_INFO54 info = SAMPLE_COMPUTER_INFO
@@ -104,10 +101,7 @@
104 @defer.inlineCallbacks101 @defer.inlineCallbacks
105 def setUp(self):102 def setUp(self):
106 yield super(RemoveDeviceTestCase, self).setUp()103 yield super(RemoveDeviceTestCase, self).setUp()
107 FakedConfirmDialog.response = gui.NO104 FakedDialog.response = gui.YES
108 FakedConfirmDialog.args = None
109 FakedConfirmDialog.kwargs = None
110 self.patch(gui.QtGui, 'QMessageBox', FakedConfirmDialog)
111105
112 def test_remove_device_opens_confirmation_dialog(self):106 def test_remove_device_opens_confirmation_dialog(self):
113 """A confirmation dialog is opened when user clicks 'delete device'."""107 """A confirmation dialog is opened when user clicks 'delete device'."""
@@ -115,13 +109,13 @@
115109
116 msg = gui.DEVICE_CONFIRM_REMOVE110 msg = gui.DEVICE_CONFIRM_REMOVE
117 buttons = gui.YES | gui.NO111 buttons = gui.YES | gui.NO
118 self.assertEqual(FakedConfirmDialog.args,112 self.assertEqual(FakedDialog.args,
119 (self.ui, '', msg, buttons, gui.NO))113 (self.ui, '', msg, buttons, gui.NO))
120 self.assertEqual(FakedConfirmDialog.kwargs, {})114 self.assertEqual(FakedDialog.kwargs, {})
121115
122 def test_remove_device_does_not_remove_if_answer_is_no(self):116 def test_remove_device_does_not_remove_if_answer_is_no(self):
123 """The device is not removed is answer is No."""117 """The device is not removed is answer is No."""
124 FakedConfirmDialog.response = gui.NO118 FakedDialog.response = gui.NO
125 self.ui.removed.connect(self._set_called)119 self.ui.removed.connect(self._set_called)
126 self.ui.ui.remove_device_button.click()120 self.ui.ui.remove_device_button.click()
127121
@@ -130,7 +124,7 @@
130124
131 def test_remove_device_does_remove_if_answer_is_yes(self):125 def test_remove_device_does_remove_if_answer_is_yes(self):
132 """The device is removed is answer is Yes."""126 """The device is removed is answer is Yes."""
133 FakedConfirmDialog.response = gui.YES127 FakedDialog.response = gui.YES
134 self.ui.ui.remove_device_button.click()128 self.ui.ui.remove_device_button.click()
135129
136 self.assert_backend_called('remove_device', device_id=self.device_id)130 self.assert_backend_called('remove_device', device_id=self.device_id)
@@ -144,7 +138,7 @@
144 """Fire deferred when the device was removed."""138 """Fire deferred when the device was removed."""
145 d.callback(device_id)139 d.callback(device_id)
146140
147 FakedConfirmDialog.response = gui.YES141 FakedDialog.response = gui.YES
148 self.ui.removed.connect(self._set_called)142 self.ui.removed.connect(self._set_called)
149 self.patch(self.ui.backend, 'remove_device', check)143 self.patch(self.ui.backend, 'remove_device', check)
150 self.ui.ui.remove_device_button.click()144 self.ui.ui.remove_device_button.click()
@@ -154,8 +148,16 @@
154148
155 def test_remove_device_emits_signal_when_not_removed(self):149 def test_remove_device_emits_signal_when_not_removed(self):
156 """The signal 'removeCanceled' is emitted when user cancels removal."""150 """The signal 'removeCanceled' is emitted when user cancels removal."""
157 FakedConfirmDialog.response = gui.NO151 FakedDialog.response = gui.NO
158 self.ui.removeCanceled.connect(self._set_called)152 self.ui.removeCanceled.connect(self._set_called)
159 self.ui.ui.remove_device_button.click()153 self.ui.ui.remove_device_button.click()
160154
161 self.assertEqual(self._called, ((), {}))155 self.assertEqual(self._called, ((), {}))
156
157 @defer.inlineCallbacks
158 def test_backend_error_is_handled(self):
159 """Any error from the backend is properly handled."""
160 self.patch(self.ui, 'backend', CrashyBackend())
161 yield self.ui.ui.remove_device_button.click()
162
163 self.assertTrue(self.memento.check_exception(CrashyBackendException))
162164
=== modified file 'ubuntuone/controlpanel/gui/qt/tests/test_devices.py'
--- ubuntuone/controlpanel/gui/qt/tests/test_devices.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/tests/test_devices.py 2011-09-26 18:38:27 +0000
@@ -20,10 +20,8 @@
2020
21from twisted.internet import defer21from twisted.internet import defer
2222
23from ubuntuone.controlpanel.gui import qt
24from ubuntuone.controlpanel.gui.qt import devices as gui23from ubuntuone.controlpanel.gui.qt import devices as gui
25from ubuntuone.controlpanel.gui.qt.tests import (24from ubuntuone.controlpanel.gui.qt.tests import (
26 FakedConfirmDialog,
27 SAMPLE_DEVICES_INFO,25 SAMPLE_DEVICES_INFO,
28)26)
29from ubuntuone.controlpanel.gui.qt.tests.test_ubuntuonebin import (27from ubuntuone.controlpanel.gui.qt.tests.test_ubuntuonebin import (
@@ -42,7 +40,6 @@
42 def setUp(self):40 def setUp(self):
43 yield super(DevicesPanelTestCase, self).setUp()41 yield super(DevicesPanelTestCase, self).setUp()
44 self.ui.backend.next_result = SAMPLE_DEVICES_INFO42 self.ui.backend.next_result = SAMPLE_DEVICES_INFO
45 self.patch(gui.QtGui, 'QMessageBox', FakedConfirmDialog)
4643
47 def test_is_processing_while_asking_info(self):44 def test_is_processing_while_asking_info(self):
48 """The ui is processing while the contents are loaded."""45 """The ui is processing while the contents are loaded."""
@@ -97,10 +94,8 @@
9794
98 def test_manage_devices_button(self):95 def test_manage_devices_button(self):
99 """Clicking the manage devices button opens the proper url."""96 """Clicking the manage devices button opens the proper url."""
100 self.patch(qt, 'uri_hook', self._set_called)97 self.assert_uri_hook_called(self.ui.ui.manage_devices_button,
101 self.ui.ui.manage_devices_button.click()98 gui.EDIT_DEVICES_LINK)
102
103 self.assertEqual(self._called, ((gui.EDIT_DEVICES_LINK,), {}))
10499
105 def test_remove_device_widget_after_removal(self):100 def test_remove_device_widget_after_removal(self):
106 """When a device widget was deleted, remove it from the UI."""101 """When a device widget was deleted, remove it from the UI."""
@@ -110,3 +105,13 @@
110 local_device.removed.emit()105 local_device.removed.emit()
111106
112 self.assertTrue(self.ui.ui.local_device_box.itemAt(0) is None)107 self.assertTrue(self.ui.ui.local_device_box.itemAt(0) is None)
108
109 def test_local_device_removed_signal(self):
110 """When the local device is removed, emit localDeviceRemoved signal."""
111 self.ui.localDeviceRemoved.connect(self._set_called)
112 self.ui.process_info(SAMPLE_DEVICES_INFO)
113
114 local_device = self.ui.ui.local_device_box.itemAt(0).widget()
115 local_device.removed.emit()
116
117 self.assertEqual(self._called, ((), {}))
113118
=== modified file 'ubuntuone/controlpanel/gui/qt/tests/test_folders.py'
--- ubuntuone/controlpanel/gui/qt/tests/test_folders.py 2011-08-12 19:12:08 +0000
+++ ubuntuone/controlpanel/gui/qt/tests/test_folders.py 2011-09-26 18:38:27 +0000
@@ -31,11 +31,9 @@
31 FAKE_VOLUMES_NO_FREE_SPACE_INFO,31 FAKE_VOLUMES_NO_FREE_SPACE_INFO,
32 MUSIC_FOLDER, ROOT, USER_HOME,32 MUSIC_FOLDER, ROOT, USER_HOME,
33)33)
34from ubuntuone.controlpanel.gui import qt
35from ubuntuone.controlpanel.gui.qt import folders as gui34from ubuntuone.controlpanel.gui.qt import folders as gui
36from ubuntuone.controlpanel.gui.qt.tests import (35from ubuntuone.controlpanel.gui.qt.tests import (
37 FakedConfirmDialog,36 FakedDialog,
38 FakedFileDialog,
39)37)
40from ubuntuone.controlpanel.gui.qt.tests.test_ubuntuonebin import (38from ubuntuone.controlpanel.gui.qt.tests.test_ubuntuonebin import (
41 UbuntuOneBinTestCase,39 UbuntuOneBinTestCase,
@@ -140,8 +138,10 @@
140 self.assertTrue(item is not None)138 self.assertTrue(item is not None)
141139
142 name = volume['path'].replace(USER_HOME + os.path.sep, '')140 name = volume['path'].replace(USER_HOME + os.path.sep, '')
141 expected_path = volume['path']
143 if volume['type'] == self.ui.backend.SHARE_TYPE:142 if volume['type'] == self.ui.backend.SHARE_TYPE:
144 name = volume['name']143 name = volume['name']
144 expected_path = volume['realpath']
145 label = item.text(gui.FOLDER_NAME_COL)145 label = item.text(gui.FOLDER_NAME_COL)
146 self.assertEqual(label, name)146 self.assertEqual(label, name)
147147
@@ -161,7 +161,7 @@
161 self.assertEqual(icon_name, gui.SHARE_ICON_NAME)161 self.assertEqual(icon_name, gui.SHARE_ICON_NAME)
162162
163 self.assertEqual(item.volume_id, volume['volume_id'])163 self.assertEqual(item.volume_id, volume['volume_id'])
164 self.assertEqual(item.volume_path, volume['path'])164 self.assertEqual(item.volume_path, expected_path)
165165
166 # tooltips are correct166 # tooltips are correct
167 self.assertEqual(item.toolTip(gui.FOLDER_NAME_COL), name)167 self.assertEqual(item.toolTip(gui.FOLDER_NAME_COL), name)
@@ -175,6 +175,8 @@
175 gui.FOLDER_ICON_NAME)175 gui.FOLDER_ICON_NAME)
176 self.assertEqual(button.iconSize().width(), 12)176 self.assertEqual(button.iconSize().width(), 12)
177 self.assertEqual(button.iconSize().height(), 12)177 self.assertEqual(button.iconSize().height(), 12)
178 self.assertEqual(button.isEnabled(),
179 bool(volume['subscribed']))
178180
179 treeiter += 1181 treeiter += 1
180 item = treeiter.value()182 item = treeiter.value()
@@ -245,7 +247,8 @@
245 self.ui.on_folders_itemActivated(item)247 self.ui.on_folders_itemActivated(item)
246248
247 self.assertEqual(self._called,249 self.assertEqual(self._called,
248 ((gui.FILE_URI_PREFIX + path,), {}))250 ((unicode(gui.QtCore.QUrl.fromLocalFile(path).toString()),), {}))
251 self.assertTrue(gui.QtCore.QUrl(self._called[0][0]).isValid())
249252
250 def test_clicking_on_row_handles_path_none(self):253 def test_clicking_on_row_handles_path_none(self):
251 """None paths are properly handled."""254 """None paths are properly handled."""
@@ -302,10 +305,8 @@
302305
303 def test_share_publish_button(self):306 def test_share_publish_button(self):
304 """When clicking the share/publish button, the proper url is opened."""307 """When clicking the share/publish button, the proper url is opened."""
305 self.patch(qt, 'uri_hook', self._set_called)308 self.assert_uri_hook_called(self.ui.ui.share_publish_button,
306 self.ui.ui.share_publish_button.click()309 gui.MANAGE_FILES_LINK)
307
308 self.assertEqual(self._called, ((gui.MANAGE_FILES_LINK,), {}))
309310
310311
311class FoldersPanelAddFolderTestCase(FoldersPanelTestCase):312class FoldersPanelAddFolderTestCase(FoldersPanelTestCase):
@@ -322,17 +323,6 @@
322 # reset backend state323 # reset backend state
323 self.ui.backend._called.clear()324 self.ui.backend._called.clear()
324325
325 # default response if user does nothing
326 FakedFileDialog.response = gui.QtCore.QString('')
327 FakedFileDialog.args = None
328 FakedFileDialog.kwargs = None
329 self.patch(gui.QtGui, 'QFileDialog', FakedFileDialog)
330
331 FakedConfirmDialog.response = None
332 FakedConfirmDialog.args = None
333 FakedConfirmDialog.kwargs = None
334 self.patch(gui.QtGui, 'QMessageBox', FakedConfirmDialog)
335
336 def test_not_is_processing(self):326 def test_not_is_processing(self):
337 """Before clicking the add folder button, the UI is not processing."""327 """Before clicking the add folder button, the UI is not processing."""
338 self.assertFalse(self.ui.is_processing, 'ui must not be processing')328 self.assertFalse(self.ui.is_processing, 'ui must not be processing')
@@ -356,10 +346,7 @@
356 def setUp(self):346 def setUp(self):
357 yield super(FoldersPanelSubscriptionTestCase, self).setUp()347 yield super(FoldersPanelSubscriptionTestCase, self).setUp()
358 self.patch(gui.os.path, 'exists', lambda path: True)348 self.patch(gui.os.path, 'exists', lambda path: True)
359 FakedConfirmDialog.response = gui.YES349 FakedDialog.response = gui.YES
360 FakedConfirmDialog.args = None
361 FakedConfirmDialog.kwargs = None
362 self.patch(gui.QtGui, 'QMessageBox', FakedConfirmDialog)
363350
364 self.ui.process_info(FAKE_VOLUMES_MINIMAL_INFO)351 self.ui.process_info(FAKE_VOLUMES_MINIMAL_INFO)
365 # the music folder352 # the music folder
@@ -368,6 +355,7 @@
368 @defer.inlineCallbacks355 @defer.inlineCallbacks
369 def test_on_folders_item_changed(self):356 def test_on_folders_item_changed(self):
370 """Clicking on 'subscribed' updates the folder subscription."""357 """Clicking on 'subscribed' updates the folder subscription."""
358 self.patch(self.ui, 'load', self._set_called)
371 volume = MUSIC_FOLDER359 volume = MUSIC_FOLDER
372 fid = volume['volume_id']360 fid = volume['volume_id']
373 subscribed = not bool(volume['subscribed'])361 subscribed = not bool(volume['subscribed'])
@@ -386,6 +374,9 @@
386 value = self.item.checkState(gui.SUBSCRIPTION_COL) == gui.CHECKED374 value = self.item.checkState(gui.SUBSCRIPTION_COL) == gui.CHECKED
387 self.assertEqual(value, bool(subscribed))375 self.assertEqual(value, bool(subscribed))
388376
377 # folder list was reloaded
378 self.assertEqual(self._called, ((), {}))
379
389 @defer.inlineCallbacks380 @defer.inlineCallbacks
390 def test_on_folders_item_changed_is_processing(self):381 def test_on_folders_item_changed_is_processing(self):
391 """Clicking on 'subscribed' sets is_processing flag until done."""382 """Clicking on 'subscribed' sets is_processing flag until done."""
@@ -438,9 +429,9 @@
438 volume_path = self.item.volume_path429 volume_path = self.item.volume_path
439 msg = gui.FOLDERS_CONFIRM_MERGE % {'folder_path': volume_path}430 msg = gui.FOLDERS_CONFIRM_MERGE % {'folder_path': volume_path}
440 buttons = gui.YES | gui.NO | gui.CANCEL431 buttons = gui.YES | gui.NO | gui.CANCEL
441 self.assertEqual(FakedConfirmDialog.args,432 self.assertEqual(FakedDialog.args,
442 (self.ui, '', msg, buttons, gui.YES))433 (self.ui, '', msg, buttons, gui.YES))
443 self.assertEqual(FakedConfirmDialog.kwargs, {})434 self.assertEqual(FakedDialog.kwargs, {})
444435
445 @defer.inlineCallbacks436 @defer.inlineCallbacks
446 def test_confirm_dialog_if_path_does_not_exist(self):437 def test_confirm_dialog_if_path_does_not_exist(self):
@@ -454,14 +445,13 @@
454445
455 yield self.ui.on_folders_itemChanged(self.item)446 yield self.ui.on_folders_itemChanged(self.item)
456447
457 self.assertEqual(FakedConfirmDialog.args, None)448 self.assertEqual(FakedDialog.args, None)
458 self.assertEqual(FakedConfirmDialog.kwargs, None)449 self.assertEqual(FakedDialog.kwargs, None)
459450
460 @defer.inlineCallbacks451 @defer.inlineCallbacks
461 def test_subscribe_does_not_call_backend_if_dialog_closed(self):452 def test_subscribe_does_not_call_backend_if_dialog_closed(self):
462 """Backend is not called if users closes the confirmation dialog."""453 """Backend is not called if users closes the confirmation dialog."""
463 FakedConfirmDialog.response = gui.CANCEL454 FakedDialog.response = gui.CANCEL
464 self.patch(gui.QtGui, 'QMessageBox', FakedConfirmDialog)
465455
466 # make sure the item is subscribed456 # make sure the item is subscribed
467 self.ui.is_processing = True457 self.ui.is_processing = True
@@ -470,7 +460,7 @@
470460
471 yield self.ui.on_folders_itemChanged(self.item)461 yield self.ui.on_folders_itemChanged(self.item)
472462
473 self.assertFalse(FakedConfirmDialog.args is None, 'warning was called')463 self.assertFalse(FakedDialog.args is None, 'warning was called')
474 self.assertNotIn('change_volume_settings', self.ui.backend._called)464 self.assertNotIn('change_volume_settings', self.ui.backend._called)
475 self.assertFalse(self.ui.is_processing)465 self.assertFalse(self.ui.is_processing)
476466
@@ -480,8 +470,7 @@
480 @defer.inlineCallbacks470 @defer.inlineCallbacks
481 def test_subscribe_does_not_call_backend_if_answer_is_no(self):471 def test_subscribe_does_not_call_backend_if_answer_is_no(self):
482 """Backend is not called if users clicks on 'No'."""472 """Backend is not called if users clicks on 'No'."""
483 FakedConfirmDialog.response = gui.NO473 FakedDialog.response = gui.NO
484 self.patch(gui.QtGui, 'QMessageBox', FakedConfirmDialog)
485474
486 # make sure the item is subscribed475 # make sure the item is subscribed
487 self.ui.is_processing = True476 self.ui.is_processing = True
@@ -490,7 +479,7 @@
490479
491 yield self.ui.on_folders_itemChanged(self.item)480 yield self.ui.on_folders_itemChanged(self.item)
492481
493 self.assertFalse(FakedConfirmDialog.args is None, 'warning was called')482 self.assertFalse(FakedDialog.args is None, 'warning was called')
494 self.assertNotIn('change_volume_settings', self.ui.backend._called)483 self.assertNotIn('change_volume_settings', self.ui.backend._called)
495 self.assertFalse(self.ui.is_processing)484 self.assertFalse(self.ui.is_processing)
496485
@@ -506,10 +495,10 @@
506 self.ui.is_processing = False495 self.ui.is_processing = False
507496
508 # the confirm dialog was not called so far497 # the confirm dialog was not called so far
509 assert FakedConfirmDialog.args is None498 assert FakedDialog.args is None
510 assert FakedConfirmDialog.kwargs is None499 assert FakedDialog.kwargs is None
511500
512 yield self.ui.on_folders_itemChanged(self.item)501 yield self.ui.on_folders_itemChanged(self.item)
513502
514 self.assertTrue(FakedConfirmDialog.args is None, 'dialog was not run')503 self.assertTrue(FakedDialog.args is None, 'dialog was not run')
515 self.assertTrue(FakedConfirmDialog.kwargs is None, 'dialog was hid')504 self.assertTrue(FakedDialog.kwargs is None, 'dialog was hid')
516505
=== modified file 'ubuntuone/controlpanel/gui/qt/tests/test_gotoweb.py'
--- ubuntuone/controlpanel/gui/qt/tests/test_gotoweb.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/tests/test_gotoweb.py 2011-09-26 18:38:27 +0000
@@ -20,7 +20,7 @@
2020
21from twisted.internet import defer21from twisted.internet import defer
2222
23from ubuntuone.controlpanel.gui import qt23from ubuntuone.controlpanel.gui import qt, UBUNTUONE_LINK
24from ubuntuone.controlpanel.gui.qt import gotoweb as gui24from ubuntuone.controlpanel.gui.qt import gotoweb as gui
25from ubuntuone.controlpanel.gui.qt.tests import (25from ubuntuone.controlpanel.gui.qt.tests import (
26 BaseTestCase,26 BaseTestCase,
@@ -35,7 +35,6 @@
35 @defer.inlineCallbacks35 @defer.inlineCallbacks
36 def setUp(self):36 def setUp(self):
37 yield super(GoToWebButtonTestCase, self).setUp()37 yield super(GoToWebButtonTestCase, self).setUp()
38 self.patch(qt, 'uri_hook', self._set_called)
3938
40 def test_uri_can_be_set(self):39 def test_uri_can_be_set(self):
41 """The uri can be set."""40 """The uri can be set."""
@@ -47,8 +46,14 @@
47 """The layout direction is RightToLeft."""46 """The layout direction is RightToLeft."""
48 self.assertEqual(self.ui.layoutDirection(), gui.QtCore.Qt.RightToLeft)47 self.assertEqual(self.ui.layoutDirection(), gui.QtCore.Qt.RightToLeft)
4948
49 def test_cursor_pointer(self):
50 """The cursor is PointingHandCursor."""
51 self.assertEqual(self.ui.cursor().shape(),
52 gui.QtCore.Qt.PointingHandCursor)
53
50 def test_open_uri_when_clicked(self):54 def test_open_uri_when_clicked(self):
51 """When clicking the button, the uri is opened."""55 """When clicking the button, the uri is opened."""
56 self.patch(qt, 'uri_hook', self._set_called)
52 self.ui.uri = 'yadda-yadda-yoo'57 self.ui.uri = 'yadda-yadda-yoo'
53 self.ui.click()58 self.ui.click()
5459
@@ -56,7 +61,54 @@
5661
57 def test_do_nothing_on_clicked_if_uri_is_none(self):62 def test_do_nothing_on_clicked_if_uri_is_none(self):
58 """When clicking the button, if the uri is None, do nothing."""63 """When clicking the button, if the uri is None, do nothing."""
64 self.patch(qt, 'uri_hook', self._set_called)
59 self.ui.uri = None65 self.ui.uri = None
60 self.ui.click()66 self.ui.click()
6167
62 self.assertEqual(self._called, False)68 self.assertEqual(self._called, False)
69
70
71class SignUrlTestCase(GoToWebButtonTestCase):
72 """The test suite for the sign url management."""
73
74 @defer.inlineCallbacks
75 def setUp(self):
76 yield super(SignUrlTestCase, self).setUp()
77 self.patch(qt, 'uri_hook', lambda url: None)
78 self.patch(gui, 'sign_url', self._set_called)
79 self.creds = yield self.ui.backend.get_credentials()
80 assert len(self.creds) > 0
81
82 def test_without_ubuntuone_prefix(self):
83 """If given url is not an ubuntuone url, don't sign it."""
84 self.ui.uri = 'bad_prefix' + UBUNTUONE_LINK
85 self.ui.click()
86
87 self.assertFalse(self._called)
88
89 def test_with_ubuntuone_prefix(self):
90 """If given url is an ubuntuone url, sign it."""
91 self.ui.uri = UBUNTUONE_LINK + 'foo'
92 self.ui.click()
93
94 self.assertEqual(self._called, ((self.ui.uri, self.creds,), {}))
95
96
97class SignUrlNoCredsTestCase(SignUrlTestCase):
98 """The test suite for the sign url management when there are no creds."""
99
100 @defer.inlineCallbacks
101 def setUp(self):
102 yield super(SignUrlNoCredsTestCase, self).setUp()
103 self.patch(self.ui.backend, 'get_credentials', lambda: {})
104
105 def test_with_ubuntuone_prefix(self):
106 """If given url is an ubuntuone url, don't sign it.
107
108 Since we have no credentials, the url should not be signed.
109
110 """
111 self.ui.uri = UBUNTUONE_LINK + 'foo'
112 self.ui.click()
113
114 self.assertFalse(self._called)
63115
=== modified file 'ubuntuone/controlpanel/gui/qt/tests/test_gui.py'
--- ubuntuone/controlpanel/gui/qt/tests/test_gui.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/tests/test_gui.py 2011-09-26 18:38:27 +0000
@@ -41,3 +41,10 @@
41 self.ui.close_callback = None41 self.ui.close_callback = None
42 self.ui.closeEvent(event=gui.QtGui.QCloseEvent())42 self.ui.closeEvent(event=gui.QtGui.QCloseEvent())
43 # world did not explode43 # world did not explode
44
45 def test_on_signin_canceled(self):
46 """On SigninPanel's signinCanceled, close."""
47 self.patch(self.ui, 'closeEvent', self._set_called)
48 self.ui.ui.control_panel.ui.signin.signinCanceled.emit()
49 self.assertEqual(len(self._called[0]), 1)
50 self.assertIsInstance(self._called[0][0], gui.QtGui.QCloseEvent)
4451
=== added file 'ubuntuone/controlpanel/gui/qt/tests/test_signin.py'
--- ubuntuone/controlpanel/gui/qt/tests/test_signin.py 1970-01-01 00:00:00 +0000
+++ ubuntuone/controlpanel/gui/qt/tests/test_signin.py 2011-09-26 18:38:27 +0000
@@ -0,0 +1,168 @@
1# -*- coding: utf-8 -*-
2
3# Authors: Natalia B Bidart <natalia.bidart@canonical.com>
4#
5# Copyright 2011 Canonical Ltd.
6#
7# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranties of
13# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14# PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program. If not, see <http://www.gnu.org/licenses/>.
18
19"""Tests for the Sign In Panel."""
20
21from twisted.internet import defer
22
23from ubuntuone.controlpanel.gui import qt
24from ubuntuone.controlpanel.gui.qt import signin as gui
25from ubuntuone.controlpanel.gui.qt.tests import (
26 CrashyBackend,
27 CrashyBackendException,
28)
29from ubuntuone.controlpanel.gui.qt.tests.test_ubuntuonebin import (
30 UbuntuOneBinTestCase,
31)
32
33EMAIL = 'foo@bar.com'
34PASSWORD = 'h3ll0World'
35TOKEN = {'yadda': 'doo'}
36
37MSG = {u'errtype': u'AuthenticationError',
38 u'message': u'The authentication failed.'}
39
40
41def fail(*a, **kw):
42 """Emit CredentialsError."""
43 raise TypeError(MSG)
44
45
46class BaseSignInPanelTestCase(UbuntuOneBinTestCase):
47 """Test the signin panel."""
48
49 innerclass_ui = gui.signin_ui
50 innerclass_name = "Ui_Form"
51 class_ui = gui.SignInPanel
52 logger = gui.logger
53
54 @defer.inlineCallbacks
55 def setUp(self):
56 yield super(BaseSignInPanelTestCase, self).setUp()
57 self.ui.backend.next_result = TOKEN
58
59
60class SignInPanelTestCase(BaseSignInPanelTestCase):
61 """Test the signin panel."""
62
63 innerclass_ui = gui.signin_ui
64 innerclass_name = "Ui_Form"
65 class_ui = gui.SignInPanel
66
67 @defer.inlineCallbacks
68 def setUp(self):
69 yield super(SignInPanelTestCase, self).setUp()
70 self.ui.backend.next_result = TOKEN
71 self.ui.ui.email_entry.setText(gui.QtCore.QString(''))
72 self.ui.ui.password_entry.setText(gui.QtCore.QString(''))
73
74 @defer.inlineCallbacks
75 def test_is_processing_while_asking_info(self):
76 """The ui is processing while the contents are loaded."""
77 def check(email, password):
78 """The ui must be is_processing."""
79 self.assertTrue(self.ui.is_processing, 'ui must be processing')
80 return TOKEN
81
82 self.patch(self.ui.backend, 'login', check)
83
84 self.assertFalse(self.ui.is_processing)
85 yield self.ui.ui.signin_button.click()
86 self.assertFalse(self.ui.is_processing)
87
88 def test_signin_disabled_at_startup(self):
89 """The signin_button is disabled at startup."""
90 self.assertFalse(self.ui.ui.signin_button.isEnabled())
91
92 def test_signin_disabled_if_no_email_but_password(self):
93 """Disable signin_button if no email."""
94 self.ui.ui.password_entry.setText(gui.QtCore.QString('doo'))
95 self.assertFalse(self.ui.ui.signin_button.isEnabled())
96
97 def test_signin_disabled_if_no_password_but_email(self):
98 """Disable signin_button if no password."""
99 self.ui.ui.email_entry.setText(gui.QtCore.QString('duh'))
100 self.assertFalse(self.ui.ui.signin_button.isEnabled())
101
102 def test_cancel_button(self):
103 """Send a signal when the cancel button is clicked."""
104 self.ui.signinCanceled.connect(self._set_called)
105 self.ui.ui.cancel_button.click()
106 self.assertEqual(self._called, ((), {}))
107
108 def test_forgot_password_button(self):
109 """When clicking the forgot passsword btn, the proper url is opened."""
110 self.patch(qt, 'uri_hook', self._set_called)
111 self.ui.ui.forgot_password_button.click()
112
113 self.assertEqual(self._called, ((gui.RESET_PASSWORD_LINK,), {}))
114
115
116class SignInButtonPanelTestCase(BaseSignInPanelTestCase):
117 """Test the signin_button widget."""
118
119 @defer.inlineCallbacks
120 def setUp(self):
121 yield super(SignInButtonPanelTestCase, self).setUp()
122 self.ui.ui.email_entry.setText(gui.QtCore.QString(EMAIL))
123 self.ui.ui.password_entry.setText(gui.QtCore.QString(PASSWORD))
124
125 @defer.inlineCallbacks
126 def test_signin_button(self):
127 """Call the backend when the signin button is clicked."""
128 yield self.ui.ui.signin_button.click()
129
130 self.assert_backend_called('login', email=EMAIL, password=PASSWORD)
131 # pylint: disable=W0212
132 for arg in self.ui.backend._called['login'][1].itervalues():
133 self.assertIsInstance(arg, unicode) # make sure not send QString
134
135 @defer.inlineCallbacks
136 def test_signin_success(self):
137 """Emit credentialsFound on signin success."""
138 self.ui.credentialsFound.connect(self._set_called)
139 yield self.ui.ui.signin_button.click()
140
141 self.assertEqual(self._called, ((TOKEN,), {}))
142 self.assertFalse(self.ui.is_processing)
143
144 def test_signin_enabled_if_email_and_password(self):
145 """Enable signin_button if email and password are non empty."""
146 self.assertTrue(self.ui.ui.signin_button.isEnabled())
147
148 def test_return_pressed(self):
149 """On return pressed, click the signin_button."""
150 self.patch(self.ui.ui.signin_button, 'click', self._set_called)
151
152 for entry in (self.ui.ui.email_entry, self.ui.ui.password_entry):
153 entry.returnPressed.emit()
154
155 # This is failing, so we need to settle with counting recievers
156 #self.assertEqual(self._called, ((), {}))
157 receivers = entry.receivers(gui.QtCore.SIGNAL('returnPressed()'))
158 self.assertEqual(1, receivers)
159
160 self._called = False
161
162 @defer.inlineCallbacks
163 def test_backend_error_is_handled(self):
164 """Any error from the backend is properly handled."""
165 self.patch(self.ui, 'backend', CrashyBackend())
166 yield self.ui.ui.signin_button.click()
167
168 self.assertTrue(self.memento.check_exception(CrashyBackendException))
0169
=== added file 'ubuntuone/controlpanel/gui/qt/tests/test_start.py'
--- ubuntuone/controlpanel/gui/qt/tests/test_start.py 1970-01-01 00:00:00 +0000
+++ ubuntuone/controlpanel/gui/qt/tests/test_start.py 2011-09-26 18:38:27 +0000
@@ -0,0 +1,91 @@
1# -*- coding: utf-8 -*-
2
3# Author: Roberto Alsina <roberto.alsina@canonical.com>
4#
5# Copyright 2011 Canonical Ltd.
6#
7# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranties of
13# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14# PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program. If not, see <http://www.gnu.org/licenses/>.
18
19"""Tests for the start function."""
20
21from twisted.internet import defer
22
23from ubuntuone.controlpanel.gui.qt import gui
24from ubuntuone.controlpanel.gui.qt.tests import NO_OP
25from ubuntuone.controlpanel.tests import TestCase
26
27
28class FakeThing(object):
29
30 """A fake thing."""
31
32 def __init__(self):
33 self.args = []
34 self.shown = False
35
36 def __call__(self, *args, **kwargs):
37 self.args.append((args, kwargs))
38 return self
39
40 def show(self):
41 """Show."""
42 self.shown = True
43
44
45class FakeReactor(object):
46 """A fake reactor."""
47
48 def run(self):
49 """Start."""
50
51 def stop(self):
52 """Stop."""
53
54
55class StartTestCase(TestCase):
56 """Test the qt control panel."""
57
58 @defer.inlineCallbacks
59 def setUp(self):
60 yield super(StartTestCase, self).setUp()
61 self.main_window = FakeThing()
62 self.tray_icon = FakeThing()
63 self.patch(gui, "MainWindow", self.main_window)
64 self.patch(gui, "TrayIcon", self.tray_icon)
65
66 def test_minimized(self):
67 """Test behaviour with minimized=True."""
68 gui.start(NO_OP, minimized=True, with_icon=True)
69 self.assertEqual(self.tray_icon.args, [((), {'window': None})])
70 self.assertEqual(self.main_window.args, [])
71
72 def test_with_icon(self):
73 """Test behaviour with with_icon=True."""
74 gui.start(NO_OP, with_icon=True, minimized=False)
75 self.assertEqual(self.main_window.args, [((), {})])
76 self.assertEqual(self.tray_icon.args, [((),
77 {'window': self.main_window})])
78
79 def test_both_false(self):
80 """Test behaviour when with_icon and minimized are False."""
81 gui.start(NO_OP, with_icon=False, minimized=False)
82 # Should be called
83 self.assertNotEqual(self.main_window.args, [])
84 # Should not be called
85 self.assertEqual(self.tray_icon.args, [])
86
87 def test_both_true(self):
88 """Test behaviour when with_icon and minimized are True."""
89 gui.start(NO_OP, with_icon=True, minimized=True)
90 self.assertEqual(self.tray_icon.args, [((), {'window': None})])
91 self.assertEqual(self.main_window.args, [])
092
=== added file 'ubuntuone/controlpanel/gui/qt/tests/test_systray.py'
--- ubuntuone/controlpanel/gui/qt/tests/test_systray.py 1970-01-01 00:00:00 +0000
+++ ubuntuone/controlpanel/gui/qt/tests/test_systray.py 2011-09-26 18:38:27 +0000
@@ -0,0 +1,103 @@
1# -*- coding: utf-8 -*-
2
3# Author: Roberto Alsina <roberto.alsina@canonical.com>
4#
5# Copyright 2011 Canonical Ltd.
6#
7# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranties of
13# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14# PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program. If not, see <http://www.gnu.org/licenses/>.
18
19"""Tests for the notification area icon."""
20
21from PyQt4 import QtGui
22
23from ubuntuone.controlpanel.gui.qt.systray import TrayIcon
24from ubuntuone.controlpanel.tests import TestCase
25import ubuntuone.controlpanel.gui.qt.gui
26
27
28class FakeMainWindow(QtGui.QWidget):
29
30 """Fake Main Window."""
31
32 def __init__(self, *args, **kwargs):
33 self.args = (args, kwargs)
34 super(FakeMainWindow, self).__init__()
35
36
37class SystrayTestCase(TestCase):
38
39 """Test the notification area icon."""
40
41 def test_quit(self):
42 """Test the quit option in the menu."""
43 # Not done on setup, because if I patch stop
44 # after instantiation, it doesn't get called.
45 self.patch(TrayIcon, "stop", self._set_called)
46 tray = TrayIcon()
47 tray.quit.trigger()
48 self.assertEqual(self._called, ((False,), {}))
49
50 def test_restore_no_window(self):
51 """Test the restore window option in the menu, with no window."""
52 self.patch(ubuntuone.controlpanel.gui.qt.gui,
53 "MainWindow", FakeMainWindow)
54 tray = TrayIcon()
55 self.assertEqual(tray.window, None)
56 tray.restore.trigger()
57 self.assertIsInstance(tray.window, FakeMainWindow)
58 self.assertTrue(tray.window.isVisible())
59 self.assertEqual(tray.window.args, ((),
60 {'close_callback': tray.delete_window}))
61
62 def test_activate(self):
63 """Test the icon activation."""
64 tray = TrayIcon()
65 window = FakeMainWindow()
66 tray.window = window
67 self.assertFalse(tray.window.isVisible())
68 tray.activated.emit(tray.Trigger)
69 self.assertEqual(tray.window, window)
70 self.assertTrue(tray.window.isVisible())
71
72 def test_restore_window(self):
73 """Test the restore window option in the menu, with a window."""
74 tray = TrayIcon()
75 window = FakeMainWindow()
76 tray.window = window
77 self.assertFalse(tray.window.isVisible())
78 tray.restore.trigger()
79 self.assertEqual(tray.window, window)
80 self.assertTrue(tray.window.isVisible())
81
82 def test_delete_window(self):
83 """Test deleting an existing window."""
84 tray = TrayIcon()
85 window = FakeMainWindow()
86 tray.window = window
87 tray.delete_window()
88 self.assertEqual(tray.window, None)
89 self.assertFalse(window.isVisible())
90
91 def test_delete_no_window(self):
92 """Test deleting without an existing window."""
93 tray = TrayIcon()
94 tray.delete_window()
95 self.assertEqual(tray.window, None)
96
97 def test_initialization(self):
98 """Test that everything initializes correctly."""
99 tray = TrayIcon()
100 self.assertTrue(tray.isVisible())
101 self.assertEqual(tray.window, None)
102 self.assertIsInstance(tray.context_menu, QtGui.QMenu)
103 self.assertFalse(tray.icon() == None)
0104
=== modified file 'ubuntuone/controlpanel/gui/qt/tests/test_ubuntuonebin.py'
--- ubuntuone/controlpanel/gui/qt/tests/test_ubuntuonebin.py 2011-07-22 21:26:48 +0000
+++ ubuntuone/controlpanel/gui/qt/tests/test_ubuntuonebin.py 2011-09-26 18:38:27 +0000
@@ -18,25 +18,24 @@
1818
19"""Tests for the Ubuntu One Bin."""19"""Tests for the Ubuntu One Bin."""
2020
21from ubuntuone.devtools.testcase import skipIfOS21from twisted.internet import defer
2222
23from ubuntuone.controlpanel.gui.qt import ubuntuonebin as gui23from ubuntuone.controlpanel.gui.qt import ubuntuonebin as gui
24from ubuntuone.controlpanel.gui.qt.tests import BaseTestCase24from ubuntuone.controlpanel.gui.qt.tests import (
25 BaseTestCase,
26 CrashyBackend,
27 CrashyBackendException,
28)
2529
26# Attribute 'yyy' defined outside __init__, access to a protected member30# Attribute 'yyy' defined outside __init__, access to a protected member
27# pylint: disable=W0201, W021231# pylint: disable=W0201, W0212
2832
2933
30class UbuntuOneBinTestCase(BaseTestCase):34class UbuntuOneBinTestCase(BaseTestCase):
31 """Test the qt cloud folders tab."""35 """Test the Ubuntu One base widget."""
3236
33 class_ui = gui.UbuntuOneBin37 class_ui = gui.UbuntuOneBin
3438
35 def test_backend(self):
36 """Backend is created."""
37 self.assertIsInstance(self.ui.backend,
38 gui.backend.ControlBackend)
39
40 def test_is_not_processing_after_creation(self):39 def test_is_not_processing_after_creation(self):
41 """After creation, is not processing."""40 """After creation, is not processing."""
42 self.assertFalse(self.ui.is_processing)41 self.assertFalse(self.ui.is_processing)
@@ -46,22 +45,33 @@
46 """The animation is active."""45 """The animation is active."""
47 self.assertFalse(self.ui.overlay.isVisible())46 self.assertFalse(self.ui.overlay.isVisible())
4847
49 @skipIfOS('win32', 'crashes under windows, see LP: #806154')
50 def test_is_enabled_if_not_processing(self):48 def test_is_enabled_if_not_processing(self):
51 """If not processing, the UI is enabled."""49 """If not processing, the UI is enabled."""
52 self.ui.show() # need to show to test widgets visibility50 self.ui.show() # need to show to test widgets visibility
51 self.addCleanup(self.ui.hide)
5352
54 self.ui.is_processing = False53 self.ui.is_processing = False
5554
56 self.assertTrue(self.ui.isEnabled())55 self.assertTrue(self.ui.isEnabled())
57 self.assertFalse(self.ui.overlay.isVisible())56 self.assertFalse(self.ui.overlay.isVisible())
5857
59 @skipIfOS('win32', 'crashes under windows, see LP: #806154')
60 def test_is_not_enabled_if_processing(self):58 def test_is_not_enabled_if_processing(self):
61 """If processing, the UI is disabled."""59 """If processing, the UI is disabled."""
62 self.ui.show() # need to show to test widgets visibility60 self.ui.show() # need to show to test widgets visibility
61 self.addCleanup(self.ui.hide)
6362
64 self.ui.is_processing = True63 self.ui.is_processing = True
6564
66 self.assertFalse(self.ui.isEnabled())65 self.assertFalse(self.ui.isEnabled())
67 self.assertTrue(self.ui.overlay.isVisible())66 self.assertTrue(self.ui.overlay.isVisible())
67
68 @defer.inlineCallbacks
69 def test_backend_error_is_handled(self):
70 """Any error from the backend is properly handled."""
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches