Merge lp:~nataliabidart/ubuntu-sso-client/stable-3-0-update-2.99.4 into lp:ubuntu-sso-client/stable-3-0

Proposed by Natalia Bidart
Status: Merged
Approved by: Natalia Bidart
Approved revision: 825
Merged at revision: 824
Proposed branch: lp:~nataliabidart/ubuntu-sso-client/stable-3-0-update-2.99.4
Merge into: lp:ubuntu-sso-client/stable-3-0
Diff against target: 18990 lines (+9079/-5903)
104 files modified
.bzrignore (+4/-11)
bin/ubuntu-sso-login-gtk (+2/-1)
bin/ubuntu-sso-login-qt (+32/-0)
bin/ubuntu-sso-proxy-creds-qt (+33/-0)
data/gtk/ui.glade (+314/-180)
data/qt/choose_sign_in.ui (+105/-61)
data/qt/loadingoverlay.ui (+103/-0)
data/qt/network_detection.ui (+142/-0)
data/qt/proxy_credentials_dialog.ui (+316/-0)
data/qt/setup_account.ui (+640/-253)
run-tests (+23/-19)
setup.py (+29/-14)
ubuntu_sso/__init__.py (+10/-6)
ubuntu_sso/account.py (+95/-76)
ubuntu_sso/constants.py.in (+28/-0)
ubuntu_sso/credentials.py (+91/-203)
ubuntu_sso/gtk/__init__.py (+1/-3)
ubuntu_sso/gtk/gui.py (+134/-86)
ubuntu_sso/gtk/main.py (+5/-25)
ubuntu_sso/gtk/tests/__init__.py (+1/-3)
ubuntu_sso/gtk/tests/test_gui.py (+110/-110)
ubuntu_sso/gtk/tests/test_main.py (+39/-0)
ubuntu_sso/keyring/__init__.py (+17/-9)
ubuntu_sso/keyring/tests/test_common.py (+4/-5)
ubuntu_sso/keyring/tests/test_linux.py (+1/-1)
ubuntu_sso/logger.py (+22/-6)
ubuntu_sso/main/__init__.py (+80/-67)
ubuntu_sso/main/glib.py (+45/-0)
ubuntu_sso/main/linux.py (+43/-38)
ubuntu_sso/main/qt.py (+49/-0)
ubuntu_sso/main/tests/__init__.py (+8/-3)
ubuntu_sso/main/tests/test_clients.py (+8/-24)
ubuntu_sso/main/tests/test_common.py (+274/-176)
ubuntu_sso/main/windows.py (+21/-18)
ubuntu_sso/qt/__init__.py (+59/-1)
ubuntu_sso/qt/common.py (+7/-9)
ubuntu_sso/qt/controllers.py (+0/-980)
ubuntu_sso/qt/current_user_sign_in_page.py (+170/-0)
ubuntu_sso/qt/email_verification_page.py (+140/-0)
ubuntu_sso/qt/enhanced_check_box.py (+50/-0)
ubuntu_sso/qt/error_page.py (+29/-0)
ubuntu_sso/qt/forgotten_password_page.py (+182/-0)
ubuntu_sso/qt/gui.py (+70/-397)
ubuntu_sso/qt/loadingoverlay.py (+123/-0)
ubuntu_sso/qt/main.py (+31/-0)
ubuntu_sso/qt/network_detection_page.py (+79/-0)
ubuntu_sso/qt/proxy_dialog.py (+155/-0)
ubuntu_sso/qt/reset_password_page.py (+200/-0)
ubuntu_sso/qt/setup_account_page.py (+524/-0)
ubuntu_sso/qt/sign_in_page.py (+99/-0)
ubuntu_sso/qt/success_page.py (+30/-0)
ubuntu_sso/qt/tests/__init__.py (+294/-5)
ubuntu_sso/qt/tests/login_u_p.py (+16/-5)
ubuntu_sso/qt/tests/show_gui.py (+14/-13)
ubuntu_sso/qt/tests/test_controllers.py (+0/-2113)
ubuntu_sso/qt/tests/test_current_user_sign_in_page.py (+244/-0)
ubuntu_sso/qt/tests/test_email_verification.py (+211/-0)
ubuntu_sso/qt/tests/test_enchanced_line_edit.py (+3/-2)
ubuntu_sso/qt/tests/test_enhanced_check_box.py (+49/-0)
ubuntu_sso/qt/tests/test_forgotten_password.py (+239/-0)
ubuntu_sso/qt/tests/test_loadingoverlay.py (+36/-0)
ubuntu_sso/qt/tests/test_main.py (+42/-0)
ubuntu_sso/qt/tests/test_network_detection.py (+95/-0)
ubuntu_sso/qt/tests/test_proxy_dialog.py (+338/-0)
ubuntu_sso/qt/tests/test_qt_views.py (+15/-101)
ubuntu_sso/qt/tests/test_reset_password.py (+12/-6)
ubuntu_sso/qt/tests/test_setup_account.py (+385/-0)
ubuntu_sso/qt/tests/test_sign_in_page.py (+69/-0)
ubuntu_sso/qt/tests/test_ubuntu_sso_wizard.py (+94/-0)
ubuntu_sso/qt/ubuntu_sso_wizard.py (+367/-0)
ubuntu_sso/qt/ui/__init__.py (+17/-0)
ubuntu_sso/tests/__init__.py (+4/-4)
ubuntu_sso/tests/bin/show_gui (+0/-58)
ubuntu_sso/tests/bin/show_nm_state (+0/-41)
ubuntu_sso/tests/test_account.py (+162/-134)
ubuntu_sso/tests/test_credentials.py (+181/-401)
ubuntu_sso/utils/__init__.py (+100/-4)
ubuntu_sso/utils/ipc.py (+12/-6)
ubuntu_sso/utils/runner/__init__.py (+99/-0)
ubuntu_sso/utils/runner/glib.py (+76/-0)
ubuntu_sso/utils/runner/qt.py (+71/-0)
ubuntu_sso/utils/runner/tests/__init__.py (+17/-0)
ubuntu_sso/utils/runner/tests/test_qt.py (+136/-0)
ubuntu_sso/utils/runner/tests/test_runner.py (+81/-0)
ubuntu_sso/utils/runner/tx.py (+93/-0)
ubuntu_sso/utils/tcpactivation.py (+1/-3)
ubuntu_sso/utils/tests/test_common.py (+209/-6)
ubuntu_sso/utils/tests/test_ipc.py (+4/-3)
ubuntu_sso/utils/tests/test_parse_args.py (+9/-18)
ubuntu_sso/utils/tests/test_txsecrets.py (+3/-0)
ubuntu_sso/utils/ui.py (+63/-38)
ubuntu_sso/utils/webclient/__init__.py (+2/-4)
ubuntu_sso/utils/webclient/common.py (+34/-7)
ubuntu_sso/utils/webclient/gsettings.py (+19/-4)
ubuntu_sso/utils/webclient/libsoup.py (+2/-1)
ubuntu_sso/utils/webclient/qtnetwork.py (+5/-0)
ubuntu_sso/utils/webclient/restful.py (+6/-1)
ubuntu_sso/utils/webclient/tests/__init__.py (+60/-0)
ubuntu_sso/utils/webclient/tests/test_gsettings.py (+108/-0)
ubuntu_sso/utils/webclient/tests/test_restful.py (+16/-2)
ubuntu_sso/utils/webclient/tests/test_timestamp.py (+16/-32)
ubuntu_sso/utils/webclient/tests/test_webclient.py (+145/-94)
ubuntu_sso/utils/webclient/timestamp.py (+16/-10)
ubuntu_sso/utils/webclient/txweb.py (+12/-2)
To merge this branch: bzr merge lp:~nataliabidart/ubuntu-sso-client/stable-3-0-update-2.99.4
Reviewer Review Type Date Requested Status
Roberto Alsina (community) Approve
Review via email: mp+93089@code.launchpad.net

Commit message

- Updating from trunk up to revno 874:

[ Alejandro J. Cura <email address hidden> ]
  - Use parameters set in the url for the OAuth signature (LP: #927664).
  - libsoup bindings need flattening to work around nul bytes in content
    (LP: #921822).
  - Replace urllib2.Request with common web-client (LP: #884972).
  - Replace urllib2.urlopen with common web-client (LP: #884975).
  - Fix tests failing in sso with test_webclient (LP: #920591).

[ Diego Sarmentero <email address hidden> ]
  - Fixed: Qt UI: after clicking on "I've forgotten my password",
    and entering an email, nothing happens (LP: #931577).
  - Fixed: Qt UI must return ubuntu_sso.USER_SUCCESS and
    ubuntu_sso.USER_CANCELLATION accordingly (LP. #930718).
  - Fixed: Qt UI: congratulations page is empty (LP: #930720).
  - Fixed: Qt UI: "I've forgotten my password" button can not be
    clicked (LP: #930722)
  - Fixed: Qt UI must return ubuntu_sso.USER_SUCCESS and
    ubuntu_sso.USER_CANCELLATION accordingly (LP: #930718).
  - Fixed: Qt UI: when calling login or validate_email,
    should pass the ping_url (LP: #930724).
  - Added signals for the different pages, letting the wizard decide
    what to do in each case.
  - Refactor the pages and controller in sso (LP: #929686).
  - Migrate SSO Pages from the Wizard to SSO (LP: #925531).

[ Manuel de la Pena <email address hidden> ]
  - Adds the code that will load the creds from the keyring when we retry.
  - Adds the script that allows to launch the creds dialog.
    Adds tests for main.
  - Allows the creds dialog to store the credentials in the keyring
    (LP: #929451).
  - Adds the credentials dialog with nearly no functionality to the project
    (LP: #916029).
  - Adds support for username:password@domain urls in the qt implementation
    of the webclient.

[ Natalia B. Bidart <email address hidden> ]
  - Proper name in setup.py for the proxy credentials executable
    (LP: #932328).
  - No more 'Congratulations, app_name has installed' message since
    we're not installing (LP: #931574).
  - Refactored logic on setup_account_page.py to displya terms and/or
    privacy links properly (LP: #931589).
  - Unified UI parse_args and have them accepting a policy_url param
    (LP: #931464).
  - Make the UI runner use the absolute path to the UI executables
    (LP: #930651).
  - Allow callers pass a 'policy_url' parameter to use in the UIs
    (LP: #930142).
  - Execute the UI as a separated process from the sso main thread
    (LP: #919330).
  - Hold on to the Qprocess instance to avoid garbage collection
    (LP: #930140).
  - Move the ping method from the credentials module to the
    UserManagement interface (LP: #929670).
  - The Gtk UI must handle errors from dbus when calling the backend
    (LP: #929820).
  - Provide a helper to spawn programs from the main loop that is being
     used by the SSO Service (LP: #920949).
  - Install ui files consitently between Gtk and Qt (part of LP: #927994).
  - Remove unused "thread_execute" function (LP: #928581).
  - Delay twisted.internet.reactor and twisted.web import to avoid
    ReactorAlreadyInstalledError (LP: #927788).
  - Added a dedicated logger for the gui module.
  - Migrated the GTK UI to use GI bindings (LP: #801111).
  - Enabled libsoup backend for webclient so the GTK UI will work.
  - Enabled the running of all the tests using the single command
    ./run-tests.
  - Added an initial version of GLib and Qt mainloop integration
    (needed to run all the tests).
  - Provide a QT UI executable (LP: #925073).
  - Add a method to obtain an OAuth signed uri.

[ Rodney Dawes <email address hidden> ]
  - Connect the activate-link button by hand to avoid Gtk-WARNING messages.

To post a comment you must log in.
Revision history for this message
Roberto Alsina (ralsina) wrote :

+1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2011-04-11 09:38:16 +0000
3+++ .bzrignore 2012-02-14 22:04:20 +0000
4@@ -1,16 +1,9 @@
5 _trial_temp
6 data/*.service
7+MANIFEST
8 build/
9 dist/
10-MANIFEST
11 po/ubuntu-sso-client.pot
12-ubuntu_sso/qt/captcha_ui.py
13-ubuntu_sso/qt/choose_sign_in_ui.py
14-ubuntu_sso/qt/current_user_sign_in_ui.py
15-ubuntu_sso/qt/email_verification_ui.py
16-ubuntu_sso/qt/setup_account_ui.py
17-ubuntu_sso/qt/terms_and_conditions_ui.py
18-ubuntu_sso/qt/success_message_ui.py
19-ubuntu_sso/qt/error_message_ui.py
20-ubuntu_sso/qt/forgotten_password_ui.py
21-ubuntu_sso/qt/reset_password_ui.py
22+ubuntu_sso/constants.py
23+ubuntu_sso/qt/ui/*_ui.py
24+ubuntu_sso/qt/ui/*_rc.py
25
26=== modified file 'bin/ubuntu-sso-login-gtk'
27--- bin/ubuntu-sso-login-gtk 2012-01-16 21:10:12 +0000
28+++ bin/ubuntu-sso-login-gtk 2012-02-14 22:04:20 +0000
29@@ -20,7 +20,8 @@
30 # Invalid name "ubuntu-sso-login-gtk", pylint: disable=C0103
31 # Access to a protected member, pylint: disable=W0212
32
33-from ubuntu_sso.gtk.main import parse_args, main
34+from ubuntu_sso.gtk.main import main
35+from ubuntu_sso.utils.ui import parse_args
36
37 from dbus.mainloop.glib import DBusGMainLoop
38 DBusGMainLoop(set_as_default=True)
39
40=== added file 'bin/ubuntu-sso-login-qt'
41--- bin/ubuntu-sso-login-qt 1970-01-01 00:00:00 +0000
42+++ bin/ubuntu-sso-login-qt 2012-02-14 22:04:20 +0000
43@@ -0,0 +1,32 @@
44+#!/usr/bin/env python
45+# -*- coding: utf-8 -*-
46+#
47+# Copyright 2012 Canonical Ltd.
48+#
49+# This program is free software: you can redistribute it and/or modify it
50+# under the terms of the GNU General Public License version 3, as published
51+# by the Free Software Foundation.
52+#
53+# This program is distributed in the hope that it will be useful, but
54+# WITHOUT ANY WARRANTY; without even the implied warranties of
55+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
56+# PURPOSE. See the GNU General Public License for more details.
57+#
58+# You should have received a copy of the GNU General Public License along
59+# with this program. If not, see <http://www.gnu.org/licenses/>.
60+
61+"""Start the sso GTK UI."""
62+
63+# Invalid name "ubuntu-sso-login-qt", pylint: disable=C0103
64+# Access to a protected member, pylint: disable=W0212
65+
66+from ubuntu_sso.qt.main import main
67+from ubuntu_sso.utils.ui import parse_args
68+
69+from dbus.mainloop.qt import DBusQtMainLoop
70+DBusQtMainLoop(set_as_default=True)
71+
72+
73+if __name__ == "__main__":
74+ args = parse_args()
75+ main(**dict(args._get_kwargs()))
76
77=== added file 'bin/ubuntu-sso-proxy-creds-qt'
78--- bin/ubuntu-sso-proxy-creds-qt 1970-01-01 00:00:00 +0000
79+++ bin/ubuntu-sso-proxy-creds-qt 2012-02-14 22:04:20 +0000
80@@ -0,0 +1,33 @@
81+#!/usr/bin/env python
82+# -*- coding: utf-8 -*-
83+#
84+# Copyright 2012 Canonical Ltd.
85+#
86+# This program is free software: you can redistribute it and/or modify it
87+# under the terms of the GNU General Public License version 3, as published
88+# by the Free Software Foundation.
89+#
90+# This program is distributed in the hope that it will be useful, but
91+# WITHOUT ANY WARRANTY; without even the implied warranties of
92+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
93+# PURPOSE. See the GNU General Public License for more details.
94+#
95+# You should have received a copy of the GNU General Public License along
96+# with this program. If not, see <http://www.gnu.org/licenses/>.
97+
98+"""Start the QT proxy creds dialog."""
99+
100+# Invalid name, pylint: disable=C0103
101+
102+import os
103+# HACK: At the moment we need to do that until sso is refactored
104+os.environ['USE_QT_MAINLOOP'] = '1'
105+
106+# set the dbus main loop to be used
107+from dbus.mainloop.qt import DBusQtMainLoop
108+DBusQtMainLoop(set_as_default=True)
109+
110+from ubuntu_sso.qt.proxy_dialog import main
111+
112+if __name__ == "__main__":
113+ main()
114
115=== modified file 'data/gtk/ui.glade'
116--- data/gtk/ui.glade 2011-09-19 13:09:46 +0000
117+++ data/gtk/ui.glade 2012-02-14 22:04:20 +0000
118@@ -1,72 +1,14 @@
119 <?xml version="1.0" encoding="UTF-8"?>
120 <interface>
121 <requires lib="gtk+" version="2.16"/>
122- <!-- interface-naming-policy project-wide -->
123- <object class="GtkWindow" id="window">
124- <property name="border_width">10</property>
125- <property name="window_position">center</property>
126- <signal name="delete_event" handler="on_close_clicked"/>
127- <child>
128- <object class="GtkVBox" id="window_vbox">
129- <property name="visible">True</property>
130- <property name="spacing">5</property>
131- <child>
132- <object class="GtkLabel" id="header_label">
133- <property name="visible">True</property>
134- <property name="xalign">0</property>
135- <property name="label" translatable="yes">Header Label </property>
136- <property name="wrap">True</property>
137- </object>
138- <packing>
139- <property name="expand">False</property>
140- <property name="padding">5</property>
141- <property name="position">0</property>
142- </packing>
143- </child>
144- <child>
145- <object class="GtkLabel" id="help_label">
146- <property name="visible">True</property>
147- <property name="xalign">0</property>
148- <property name="label" translatable="yes">help label</property>
149- <property name="wrap">True</property>
150- </object>
151- <packing>
152- <property name="expand">False</property>
153- <property name="position">1</property>
154- </packing>
155- </child>
156- <child>
157- <object class="GtkLabel" id="warning_label">
158- <property name="visible">True</property>
159- <property name="xalign">0</property>
160- <property name="label" translatable="yes">warning label</property>
161- <property name="wrap">True</property>
162- </object>
163- <packing>
164- <property name="expand">False</property>
165- <property name="position">2</property>
166- </packing>
167- </child>
168- <child>
169- <object class="GtkNotebook" id="content">
170- <property name="visible">True</property>
171- <property name="can_focus">True</property>
172- <property name="show_tabs">False</property>
173- <property name="show_border">False</property>
174- </object>
175- <packing>
176- <property name="position">3</property>
177- </packing>
178- </child>
179- </object>
180- </child>
181- </object>
182 <object class="GtkVBox" id="enter_details_vbox">
183 <property name="visible">True</property>
184+ <property name="can_focus">False</property>
185 <property name="spacing">5</property>
186 <child>
187 <object class="GtkHBox" id="emails_hbox">
188 <property name="visible">True</property>
189+ <property name="can_focus">False</property>
190 <property name="spacing">5</property>
191 <property name="homogeneous">True</property>
192 <child>
193@@ -78,12 +20,14 @@
194 </object>
195 <packing>
196 <property name="expand">False</property>
197+ <property name="fill">True</property>
198 <property name="position">0</property>
199 </packing>
200 </child>
201 <child>
202 <object class="GtkHBox" id="passwords_hbox">
203 <property name="visible">True</property>
204+ <property name="can_focus">False</property>
205 <property name="spacing">5</property>
206 <property name="homogeneous">True</property>
207 <child>
208@@ -95,38 +39,45 @@
209 </object>
210 <packing>
211 <property name="expand">False</property>
212+ <property name="fill">True</property>
213 <property name="position">1</property>
214 </packing>
215 </child>
216 <child>
217 <object class="GtkLabel" id="password_help_label">
218 <property name="visible">True</property>
219+ <property name="can_focus">False</property>
220 <property name="label">password help</property>
221 <property name="wrap">True</property>
222 </object>
223 <packing>
224 <property name="expand">False</property>
225+ <property name="fill">True</property>
226 <property name="position">2</property>
227 </packing>
228 </child>
229 <child>
230 <object class="GtkAlignment" id="alignment5">
231 <property name="visible">True</property>
232+ <property name="can_focus">False</property>
233 <property name="xscale">0</property>
234 <property name="yscale">0</property>
235 <child>
236 <object class="GtkHBox" id="hbox1">
237 <property name="visible">True</property>
238+ <property name="can_focus">False</property>
239 <child>
240 <object class="GtkVBox" id="captcha_vbox">
241 <property name="width_request">300</property>
242 <property name="height_request">60</property>
243 <property name="visible">True</property>
244+ <property name="can_focus">False</property>
245 <child>
246 <object class="GtkEventBox" id="captcha_loading">
247 <property name="width_request">300</property>
248 <property name="height_request">60</property>
249 <property name="visible">True</property>
250+ <property name="can_focus">False</property>
251 <child>
252 <placeholder/>
253 </child>
254@@ -141,9 +92,12 @@
255 <object class="GtkImage" id="captcha_image">
256 <property name="width_request">300</property>
257 <property name="visible">True</property>
258+ <property name="can_focus">False</property>
259 <property name="stock">gtk-missing-image</property>
260 </object>
261 <packing>
262+ <property name="expand">True</property>
263+ <property name="fill">True</property>
264 <property name="position">1</property>
265 </packing>
266 </child>
267@@ -157,23 +111,28 @@
268 <child>
269 <object class="GtkVBox" id="vbox1">
270 <property name="visible">True</property>
271+ <property name="can_focus">False</property>
272 <child>
273 <object class="GtkButton" id="captcha_reload_button">
274+ <property name="use_action_appearance">False</property>
275 <property name="visible">True</property>
276 <property name="can_focus">True</property>
277 <property name="receives_default">True</property>
278+ <property name="use_action_appearance">False</property>
279 <property name="relief">none</property>
280 <property name="focus_on_click">False</property>
281- <signal name="clicked" handler="on_captcha_reload_button_clicked"/>
282+ <signal name="clicked" handler="on_captcha_reload_button_clicked" swapped="no"/>
283 <child>
284 <object class="GtkImage" id="image1">
285 <property name="visible">True</property>
286+ <property name="can_focus">False</property>
287 <property name="icon_name">reload</property>
288 </object>
289 </child>
290 </object>
291 <packing>
292 <property name="expand">False</property>
293+ <property name="fill">True</property>
294 <property name="position">0</property>
295 </packing>
296 </child>
297@@ -186,6 +145,7 @@
298 </object>
299 <packing>
300 <property name="expand">False</property>
301+ <property name="fill">True</property>
302 <property name="position">1</property>
303 </packing>
304 </child>
305@@ -194,64 +154,76 @@
306 </object>
307 <packing>
308 <property name="expand">False</property>
309+ <property name="fill">True</property>
310 <property name="position">3</property>
311 </packing>
312 </child>
313 <child>
314 <object class="GtkVBox" id="captcha_solution_vbox">
315 <property name="visible">True</property>
316+ <property name="can_focus">False</property>
317 <child>
318 <placeholder/>
319 </child>
320 </object>
321 <packing>
322 <property name="expand">False</property>
323+ <property name="fill">True</property>
324 <property name="position">4</property>
325 </packing>
326 </child>
327 <child>
328 <object class="GtkCheckButton" id="yes_to_updates_checkbutton">
329 <property name="label" translatable="yes">yes to updates</property>
330+ <property name="use_action_appearance">False</property>
331 <property name="visible">True</property>
332 <property name="can_focus">True</property>
333 <property name="receives_default">False</property>
334+ <property name="use_action_appearance">False</property>
335 <property name="active">True</property>
336 <property name="draw_indicator">True</property>
337 </object>
338 <packing>
339 <property name="expand">False</property>
340+ <property name="fill">True</property>
341 <property name="position">5</property>
342 </packing>
343 </child>
344 <child>
345 <object class="GtkVBox" id="tc_vbox">
346 <property name="visible">True</property>
347+ <property name="can_focus">False</property>
348 <property name="spacing">5</property>
349 <child>
350 <object class="GtkCheckButton" id="yes_to_tc_checkbutton">
351 <property name="label" translatable="yes">yes to tc</property>
352+ <property name="use_action_appearance">False</property>
353 <property name="visible">True</property>
354 <property name="can_focus">True</property>
355 <property name="receives_default">False</property>
356- <property name="active">False</property>
357+ <property name="use_action_appearance">False</property>
358 <property name="draw_indicator">True</property>
359 </object>
360 <packing>
361 <property name="expand">False</property>
362+ <property name="fill">True</property>
363 <property name="position">0</property>
364 </packing>
365 </child>
366 <child>
367 <object class="GtkHButtonBox" id="hbuttonbox3">
368 <property name="visible">True</property>
369+ <property name="can_focus">False</property>
370 <property name="layout_style">start</property>
371 <child>
372 <object class="GtkButton" id="tc_button">
373 <property name="label">show tc</property>
374+ <property name="use_action_appearance">False</property>
375 <property name="visible">True</property>
376 <property name="can_focus">True</property>
377 <property name="receives_default">True</property>
378- <signal name="clicked" handler="on_tc_button_clicked"/>
379+ <property name="use_action_appearance">False</property>
380+ <signal name="clicked" handler="on_tc_button_clicked" swapped="no"/>
381 </object>
382 <packing>
383 <property name="expand">False</property>
384@@ -262,42 +234,53 @@
385 </object>
386 <packing>
387 <property name="expand">False</property>
388+ <property name="fill">True</property>
389 <property name="position">1</property>
390 </packing>
391 </child>
392 <child>
393 <object class="GtkLabel" id="tc_warning_label">
394 <property name="visible">True</property>
395+ <property name="can_focus">False</property>
396 <property name="xalign">0</property>
397 <property name="label">tc warning</property>
398 <property name="wrap">True</property>
399 </object>
400 <packing>
401+ <property name="expand">True</property>
402+ <property name="fill">True</property>
403 <property name="position">2</property>
404 </packing>
405 </child>
406 </object>
407 <packing>
408 <property name="expand">False</property>
409+ <property name="fill">True</property>
410 <property name="position">6</property>
411 </packing>
412 </child>
413 <child>
414 <object class="GtkHBox" id="hbox2">
415 <property name="visible">True</property>
416+ <property name="can_focus">False</property>
417 <property name="spacing">5</property>
418 <child>
419 <object class="GtkHButtonBox" id="hbuttonbox9">
420 <property name="visible">True</property>
421+ <property name="can_focus">False</property>
422 <property name="layout_style">start</property>
423 <child>
424 <object class="GtkLinkButton" id="login_button">
425 <property name="label">login button</property>
426+ <property name="use_action_appearance">False</property>
427 <property name="visible">True</property>
428 <property name="can_focus">True</property>
429 <property name="receives_default">True</property>
430+ <property name="use_action_appearance">False</property>
431 <property name="relief">none</property>
432- <signal name="clicked" handler="on_sign_in_button_clicked"/>
433+ <property name="uri">foo</property>
434+ <signal name="activate-link" handler="on_activate_link" swapped="no"/>
435+ <signal name="clicked" handler="on_sign_in_button_clicked" swapped="no"/>
436 </object>
437 <packing>
438 <property name="expand">False</property>
439@@ -308,20 +291,24 @@
440 </object>
441 <packing>
442 <property name="expand">False</property>
443+ <property name="fill">True</property>
444 <property name="position">0</property>
445 </packing>
446 </child>
447 <child>
448 <object class="GtkHButtonBox" id="hbuttonbox1">
449 <property name="visible">True</property>
450+ <property name="can_focus">False</property>
451 <property name="spacing">5</property>
452 <property name="layout_style">end</property>
453 <child>
454 <object class="GtkButton" id="join_cancel_button">
455 <property name="label">gtk-cancel</property>
456+ <property name="use_action_appearance">False</property>
457 <property name="visible">True</property>
458 <property name="can_focus">True</property>
459 <property name="receives_default">True</property>
460+ <property name="use_action_appearance">False</property>
461 <property name="use_stock">True</property>
462 </object>
463 <packing>
464@@ -333,11 +320,13 @@
465 <child>
466 <object class="GtkButton" id="join_ok_button">
467 <property name="label">gtk-go-forward</property>
468+ <property name="use_action_appearance">False</property>
469 <property name="visible">True</property>
470 <property name="can_focus">True</property>
471 <property name="receives_default">True</property>
472+ <property name="use_action_appearance">False</property>
473 <property name="use_stock">True</property>
474- <signal name="clicked" handler="on_join_ok_button_clicked"/>
475+ <signal name="clicked" handler="on_join_ok_button_clicked" swapped="no"/>
476 </object>
477 <packing>
478 <property name="expand">False</property>
479@@ -348,6 +337,7 @@
480 </object>
481 <packing>
482 <property name="expand">False</property>
483+ <property name="fill">True</property>
484 <property name="pack_type">end</property>
485 <property name="position">1</property>
486 </packing>
487@@ -355,122 +345,72 @@
488 </object>
489 <packing>
490 <property name="expand">False</property>
491+ <property name="fill">True</property>
492 <property name="pack_type">end</property>
493 <property name="position">7</property>
494 </packing>
495 </child>
496 </object>
497- <object class="GtkVBox" id="processing_vbox">
498- <property name="visible">True</property>
499- <property name="spacing">10</property>
500- <child>
501- <placeholder/>
502- </child>
503- </object>
504- <object class="GtkVBox" id="verify_email_vbox">
505- <property name="visible">True</property>
506- <property name="spacing">10</property>
507- <child>
508- <object class="GtkAlignment" id="alignment4">
509- <property name="visible">True</property>
510- <property name="xscale">0</property>
511- <property name="yscale">0</property>
512- <child>
513- <object class="GtkVBox" id="verify_email_details_vbox">
514- <property name="visible">True</property>
515- <child>
516- <placeholder/>
517- </child>
518- </object>
519- </child>
520- </object>
521- <packing>
522- <property name="position">0</property>
523- </packing>
524- </child>
525- <child>
526- <object class="GtkHButtonBox" id="hbuttonbox2">
527- <property name="visible">True</property>
528- <property name="spacing">5</property>
529- <property name="layout_style">end</property>
530- <child>
531- <object class="GtkButton" id="verify_token_button">
532- <property name="label">gtk-ok</property>
533- <property name="visible">True</property>
534- <property name="can_focus">True</property>
535- <property name="receives_default">True</property>
536- <property name="use_stock">True</property>
537- <signal name="clicked" handler="on_verify_token_button_clicked"/>
538- </object>
539- <packing>
540- <property name="expand">False</property>
541- <property name="fill">False</property>
542- <property name="position">0</property>
543- </packing>
544- </child>
545- </object>
546- <packing>
547- <property name="expand">False</property>
548- <property name="position">1</property>
549- </packing>
550- </child>
551- </object>
552- <object class="GtkVBox" id="tc_browser_vbox">
553- <property name="visible">True</property>
554- <signal name="hide" handler="on_tc_browser_vbox_hide"/>
555- <child>
556- <object class="GtkScrolledWindow" id="tc_browser_window">
557- <property name="visible">True</property>
558- <property name="can_focus">True</property>
559- <property name="border_width">10</property>
560- <property name="hscrollbar_policy">never</property>
561- <property name="vscrollbar_policy">automatic</property>
562- <property name="shadow_type">in</property>
563- <child>
564- <placeholder/>
565- </child>
566- </object>
567- <packing>
568- <property name="position">0</property>
569- </packing>
570- </child>
571- <child>
572- <object class="GtkHButtonBox" id="hbuttonbox4">
573- <property name="visible">True</property>
574- <property name="layout_style">end</property>
575- <child>
576- <object class="GtkButton" id="tc_back_button">
577- <property name="label">gtk-go-back</property>
578- <property name="visible">True</property>
579- <property name="can_focus">True</property>
580- <property name="receives_default">True</property>
581- <property name="use_stock">True</property>
582- <signal name="clicked" handler="on_tc_back_button_clicked"/>
583- </object>
584- <packing>
585- <property name="expand">False</property>
586- <property name="fill">False</property>
587- <property name="position">0</property>
588- </packing>
589- </child>
590- </object>
591- <packing>
592- <property name="expand">False</property>
593+ <object class="GtkVBox" id="finish_vbox">
594+ <property name="visible">True</property>
595+ <property name="can_focus">False</property>
596+ <property name="spacing">10</property>
597+ <child>
598+ <object class="GtkLabel" id="finish_label">
599+ <property name="visible">True</property>
600+ <property name="can_focus">False</property>
601+ <property name="wrap">True</property>
602+ </object>
603+ <packing>
604+ <property name="expand">True</property>
605+ <property name="fill">True</property>
606+ <property name="position">0</property>
607+ </packing>
608+ </child>
609+ <child>
610+ <object class="GtkHButtonBox" id="hbuttonbox8">
611+ <property name="visible">True</property>
612+ <property name="can_focus">False</property>
613+ <property name="layout_style">end</property>
614+ <child>
615+ <object class="GtkButton" id="finish_close_button">
616+ <property name="label">gtk-close</property>
617+ <property name="use_action_appearance">False</property>
618+ <property name="visible">True</property>
619+ <property name="can_focus">True</property>
620+ <property name="receives_default">True</property>
621+ <property name="use_action_appearance">False</property>
622+ <property name="use_stock">True</property>
623+ <signal name="clicked" handler="on_close_clicked" swapped="no"/>
624+ </object>
625+ <packing>
626+ <property name="expand">False</property>
627+ <property name="fill">False</property>
628+ <property name="position">0</property>
629+ </packing>
630+ </child>
631+ </object>
632+ <packing>
633+ <property name="expand">False</property>
634+ <property name="fill">True</property>
635 <property name="position">1</property>
636 </packing>
637 </child>
638 </object>
639 <object class="GtkVBox" id="login_vbox">
640 <property name="visible">True</property>
641+ <property name="can_focus">False</property>
642 <property name="spacing">10</property>
643 <child>
644 <object class="GtkAlignment" id="alignment3">
645 <property name="visible">True</property>
646+ <property name="can_focus">False</property>
647 <property name="xscale">0</property>
648 <property name="yscale">0</property>
649 <child>
650 <object class="GtkVBox" id="login_details_vbox">
651 <property name="visible">True</property>
652+ <property name="can_focus">False</property>
653 <property name="spacing">5</property>
654 <child>
655 <placeholder/>
656@@ -482,26 +422,34 @@
657 </child>
658 </object>
659 <packing>
660+ <property name="expand">True</property>
661+ <property name="fill">True</property>
662 <property name="position">0</property>
663 </packing>
664 </child>
665 <child>
666 <object class="GtkHBox" id="hbox3">
667 <property name="visible">True</property>
668+ <property name="can_focus">False</property>
669 <property name="spacing">5</property>
670 <child>
671 <object class="GtkHButtonBox" id="hbuttonbox10">
672 <property name="visible">True</property>
673+ <property name="can_focus">False</property>
674 <property name="layout_style">start</property>
675 <child>
676 <object class="GtkLinkButton" id="forgotten_password_button">
677- <property name="label" translatable="yes">button</property>
678+ <property name="label" translatable="yes">forgot password button</property>
679+ <property name="use_action_appearance">False</property>
680 <property name="visible">True</property>
681 <property name="can_focus">True</property>
682 <property name="receives_default">True</property>
683 <property name="has_tooltip">True</property>
684+ <property name="use_action_appearance">False</property>
685 <property name="relief">none</property>
686- <signal name="clicked" handler="on_forgotten_password_button_clicked"/>
687+ <property name="uri">foo</property>
688+ <signal name="activate-link" handler="on_activate_link" swapped="no"/>
689+ <signal name="clicked" handler="on_forgotten_password_button_clicked" swapped="no"/>
690 </object>
691 <packing>
692 <property name="expand">False</property>
693@@ -513,20 +461,24 @@
694 </object>
695 <packing>
696 <property name="expand">False</property>
697+ <property name="fill">True</property>
698 <property name="position">0</property>
699 </packing>
700 </child>
701 <child>
702 <object class="GtkHButtonBox" id="hbuttonbox5">
703 <property name="visible">True</property>
704+ <property name="can_focus">False</property>
705 <property name="spacing">5</property>
706 <property name="layout_style">end</property>
707 <child>
708 <object class="GtkButton" id="login_cancel_button">
709 <property name="label">gtk-cancel</property>
710+ <property name="use_action_appearance">False</property>
711 <property name="visible">True</property>
712 <property name="can_focus">True</property>
713 <property name="receives_default">True</property>
714+ <property name="use_action_appearance">False</property>
715 <property name="use_stock">True</property>
716 </object>
717 <packing>
718@@ -538,11 +490,13 @@
719 <child>
720 <object class="GtkButton" id="login_back_button">
721 <property name="label">gtk-go-back</property>
722+ <property name="use_action_appearance">False</property>
723 <property name="visible">True</property>
724 <property name="can_focus">True</property>
725 <property name="receives_default">True</property>
726+ <property name="use_action_appearance">False</property>
727 <property name="use_stock">True</property>
728- <signal name="clicked" handler="on_login_back_button_clicked"/>
729+ <signal name="clicked" handler="on_login_back_button_clicked" swapped="no"/>
730 </object>
731 <packing>
732 <property name="expand">False</property>
733@@ -553,11 +507,13 @@
734 <child>
735 <object class="GtkButton" id="login_ok_button">
736 <property name="label">gtk-connect</property>
737+ <property name="use_action_appearance">False</property>
738 <property name="visible">True</property>
739 <property name="can_focus">True</property>
740 <property name="receives_default">True</property>
741+ <property name="use_action_appearance">False</property>
742 <property name="use_stock">True</property>
743- <signal name="clicked" handler="on_login_connect_button_clicked"/>
744+ <signal name="clicked" handler="on_login_connect_button_clicked" swapped="no"/>
745 </object>
746 <packing>
747 <property name="expand">False</property>
748@@ -568,6 +524,7 @@
749 </object>
750 <packing>
751 <property name="expand">False</property>
752+ <property name="fill">True</property>
753 <property name="pack_type">end</property>
754 <property name="position">1</property>
755 </packing>
756@@ -575,21 +532,33 @@
757 </object>
758 <packing>
759 <property name="expand">False</property>
760+ <property name="fill">True</property>
761 <property name="position">1</property>
762 </packing>
763 </child>
764 </object>
765+ <object class="GtkVBox" id="processing_vbox">
766+ <property name="visible">True</property>
767+ <property name="can_focus">False</property>
768+ <property name="spacing">10</property>
769+ <child>
770+ <placeholder/>
771+ </child>
772+ </object>
773 <object class="GtkVBox" id="request_password_token_vbox">
774 <property name="visible">True</property>
775+ <property name="can_focus">False</property>
776 <property name="spacing">10</property>
777 <child>
778 <object class="GtkAlignment" id="alignment2">
779 <property name="visible">True</property>
780+ <property name="can_focus">False</property>
781 <property name="xscale">0</property>
782 <property name="yscale">0</property>
783 <child>
784 <object class="GtkVBox" id="request_password_token_details_vbox">
785 <property name="visible">True</property>
786+ <property name="can_focus">False</property>
787 <property name="spacing">5</property>
788 <child>
789 <placeholder/>
790@@ -598,20 +567,25 @@
791 </child>
792 </object>
793 <packing>
794+ <property name="expand">True</property>
795+ <property name="fill">True</property>
796 <property name="position">0</property>
797 </packing>
798 </child>
799 <child>
800 <object class="GtkHButtonBox" id="hbuttonbox7">
801 <property name="visible">True</property>
802+ <property name="can_focus">False</property>
803 <property name="spacing">5</property>
804 <property name="layout_style">end</property>
805 <child>
806 <object class="GtkButton" id="request_password_token_cancel_button">
807 <property name="label">gtk-cancel</property>
808+ <property name="use_action_appearance">False</property>
809 <property name="visible">True</property>
810 <property name="can_focus">True</property>
811 <property name="receives_default">True</property>
812+ <property name="use_action_appearance">False</property>
813 <property name="use_stock">True</property>
814 </object>
815 <packing>
816@@ -623,11 +597,13 @@
817 <child>
818 <object class="GtkButton" id="request_password_token_back_button">
819 <property name="label">gtk-go-back</property>
820+ <property name="use_action_appearance">False</property>
821 <property name="visible">True</property>
822 <property name="can_focus">True</property>
823 <property name="receives_default">True</property>
824+ <property name="use_action_appearance">False</property>
825 <property name="use_stock">True</property>
826- <signal name="clicked" handler="on_request_password_token_back_button_clicked"/>
827+ <signal name="clicked" handler="on_request_password_token_back_button_clicked" swapped="no"/>
828 </object>
829 <packing>
830 <property name="expand">False</property>
831@@ -638,11 +614,13 @@
832 <child>
833 <object class="GtkButton" id="request_password_token_ok_button">
834 <property name="label">gtk-ok</property>
835+ <property name="use_action_appearance">False</property>
836 <property name="visible">True</property>
837 <property name="can_focus">True</property>
838 <property name="receives_default">True</property>
839+ <property name="use_action_appearance">False</property>
840 <property name="use_stock">True</property>
841- <signal name="clicked" handler="on_request_password_token_ok_button_clicked"/>
842+ <signal name="clicked" handler="on_request_password_token_ok_button_clicked" swapped="no"/>
843 </object>
844 <packing>
845 <property name="expand">False</property>
846@@ -653,35 +631,42 @@
847 </object>
848 <packing>
849 <property name="expand">False</property>
850+ <property name="fill">True</property>
851 <property name="position">1</property>
852 </packing>
853 </child>
854 </object>
855 <object class="GtkVBox" id="set_new_password_vbox">
856 <property name="visible">True</property>
857+ <property name="can_focus">False</property>
858 <property name="spacing">10</property>
859 <child>
860 <object class="GtkVBox" id="vbox2">
861 <property name="visible">True</property>
862+ <property name="can_focus">False</property>
863 <child>
864 <object class="GtkLabel" id="reset_password_help_label">
865 <property name="visible">True</property>
866+ <property name="can_focus">False</property>
867 <property name="label">label</property>
868 <property name="wrap">True</property>
869 </object>
870 <packing>
871 <property name="expand">False</property>
872+ <property name="fill">True</property>
873 <property name="position">0</property>
874 </packing>
875 </child>
876 <child>
877 <object class="GtkAlignment" id="alignment1">
878 <property name="visible">True</property>
879+ <property name="can_focus">False</property>
880 <property name="xscale">0</property>
881 <property name="yscale">0</property>
882 <child>
883 <object class="GtkVBox" id="set_new_password_details_vbox">
884 <property name="visible">True</property>
885+ <property name="can_focus">False</property>
886 <property name="spacing">5</property>
887 <child>
888 <placeholder/>
889@@ -696,25 +681,32 @@
890 </child>
891 </object>
892 <packing>
893+ <property name="expand">True</property>
894+ <property name="fill">True</property>
895 <property name="position">1</property>
896 </packing>
897 </child>
898 </object>
899 <packing>
900+ <property name="expand">True</property>
901+ <property name="fill">True</property>
902 <property name="position">0</property>
903 </packing>
904 </child>
905 <child>
906 <object class="GtkHButtonBox" id="hbuttonbox6">
907 <property name="visible">True</property>
908+ <property name="can_focus">False</property>
909 <property name="spacing">5</property>
910 <property name="layout_style">end</property>
911 <child>
912 <object class="GtkButton" id="set_new_password_cancel_button">
913 <property name="label">gtk-cancel</property>
914+ <property name="use_action_appearance">False</property>
915 <property name="visible">True</property>
916 <property name="can_focus">True</property>
917 <property name="receives_default">True</property>
918+ <property name="use_action_appearance">False</property>
919 <property name="use_stock">True</property>
920 </object>
921 <packing>
922@@ -726,11 +718,13 @@
923 <child>
924 <object class="GtkButton" id="set_new_password_ok_button">
925 <property name="label">gtk-ok</property>
926+ <property name="use_action_appearance">False</property>
927 <property name="visible">True</property>
928 <property name="can_focus">True</property>
929 <property name="receives_default">True</property>
930+ <property name="use_action_appearance">False</property>
931 <property name="use_stock">True</property>
932- <signal name="clicked" handler="on_set_new_password_ok_button_clicked"/>
933+ <signal name="clicked" handler="on_set_new_password_ok_button_clicked" swapped="no"/>
934 </object>
935 <packing>
936 <property name="expand">False</property>
937@@ -741,34 +735,104 @@
938 </object>
939 <packing>
940 <property name="expand">False</property>
941- <property name="position">1</property>
942- </packing>
943- </child>
944- </object>
945- <object class="GtkVBox" id="finish_vbox">
946- <property name="visible">True</property>
947+ <property name="fill">True</property>
948+ <property name="position">1</property>
949+ </packing>
950+ </child>
951+ </object>
952+ <object class="GtkVBox" id="tc_browser_vbox">
953+ <property name="visible">True</property>
954+ <property name="can_focus">False</property>
955+ <signal name="hide" handler="on_tc_browser_vbox_hide" swapped="no"/>
956+ <child>
957+ <object class="GtkScrolledWindow" id="tc_browser_window">
958+ <property name="visible">True</property>
959+ <property name="can_focus">True</property>
960+ <property name="border_width">10</property>
961+ <property name="hscrollbar_policy">never</property>
962+ <property name="shadow_type">in</property>
963+ <child>
964+ <placeholder/>
965+ </child>
966+ </object>
967+ <packing>
968+ <property name="expand">True</property>
969+ <property name="fill">True</property>
970+ <property name="position">0</property>
971+ </packing>
972+ </child>
973+ <child>
974+ <object class="GtkHButtonBox" id="hbuttonbox4">
975+ <property name="visible">True</property>
976+ <property name="can_focus">False</property>
977+ <property name="layout_style">end</property>
978+ <child>
979+ <object class="GtkButton" id="tc_back_button">
980+ <property name="label">gtk-go-back</property>
981+ <property name="use_action_appearance">False</property>
982+ <property name="visible">True</property>
983+ <property name="can_focus">True</property>
984+ <property name="receives_default">True</property>
985+ <property name="use_action_appearance">False</property>
986+ <property name="use_stock">True</property>
987+ <signal name="clicked" handler="on_tc_back_button_clicked" swapped="no"/>
988+ </object>
989+ <packing>
990+ <property name="expand">False</property>
991+ <property name="fill">False</property>
992+ <property name="position">0</property>
993+ </packing>
994+ </child>
995+ </object>
996+ <packing>
997+ <property name="expand">False</property>
998+ <property name="fill">True</property>
999+ <property name="position">1</property>
1000+ </packing>
1001+ </child>
1002+ </object>
1003+ <object class="GtkVBox" id="verify_email_vbox">
1004+ <property name="visible">True</property>
1005+ <property name="can_focus">False</property>
1006 <property name="spacing">10</property>
1007 <child>
1008- <object class="GtkLabel" id="finish_label">
1009+ <object class="GtkAlignment" id="alignment4">
1010 <property name="visible">True</property>
1011- <property name="wrap">True</property>
1012+ <property name="can_focus">False</property>
1013+ <property name="xscale">0</property>
1014+ <property name="yscale">0</property>
1015+ <child>
1016+ <object class="GtkVBox" id="verify_email_details_vbox">
1017+ <property name="visible">True</property>
1018+ <property name="can_focus">False</property>
1019+ <child>
1020+ <placeholder/>
1021+ </child>
1022+ </object>
1023+ </child>
1024 </object>
1025 <packing>
1026+ <property name="expand">True</property>
1027+ <property name="fill">True</property>
1028 <property name="position">0</property>
1029 </packing>
1030 </child>
1031 <child>
1032- <object class="GtkHButtonBox" id="hbuttonbox8">
1033+ <object class="GtkHButtonBox" id="hbuttonbox2">
1034 <property name="visible">True</property>
1035+ <property name="can_focus">False</property>
1036+ <property name="spacing">5</property>
1037 <property name="layout_style">end</property>
1038 <child>
1039- <object class="GtkButton" id="finish_close_button">
1040- <property name="label">gtk-close</property>
1041+ <object class="GtkButton" id="verify_token_button">
1042+ <property name="label">gtk-ok</property>
1043+ <property name="use_action_appearance">False</property>
1044 <property name="visible">True</property>
1045 <property name="can_focus">True</property>
1046 <property name="receives_default">True</property>
1047+ <property name="use_action_appearance">False</property>
1048 <property name="use_stock">True</property>
1049- <signal name="clicked" handler="on_close_clicked"/>
1050+ <signal name="clicked" handler="on_verify_token_button_clicked" swapped="no"/>
1051 </object>
1052 <packing>
1053 <property name="expand">False</property>
1054@@ -779,8 +843,78 @@
1055 </object>
1056 <packing>
1057 <property name="expand">False</property>
1058+ <property name="fill">True</property>
1059 <property name="position">1</property>
1060 </packing>
1061 </child>
1062 </object>
1063+ <object class="GtkWindow" id="window">
1064+ <property name="can_focus">False</property>
1065+ <property name="border_width">10</property>
1066+ <property name="window_position">center</property>
1067+ <signal name="delete-event" handler="on_close_clicked" swapped="no"/>
1068+ <child>
1069+ <object class="GtkVBox" id="window_vbox">
1070+ <property name="visible">True</property>
1071+ <property name="can_focus">False</property>
1072+ <property name="spacing">5</property>
1073+ <child>
1074+ <object class="GtkLabel" id="header_label">
1075+ <property name="visible">True</property>
1076+ <property name="can_focus">False</property>
1077+ <property name="xalign">0</property>
1078+ <property name="label" translatable="yes">Header Label </property>
1079+ <property name="wrap">True</property>
1080+ </object>
1081+ <packing>
1082+ <property name="expand">False</property>
1083+ <property name="fill">True</property>
1084+ <property name="padding">5</property>
1085+ <property name="position">0</property>
1086+ </packing>
1087+ </child>
1088+ <child>
1089+ <object class="GtkLabel" id="help_label">
1090+ <property name="visible">True</property>
1091+ <property name="can_focus">False</property>
1092+ <property name="xalign">0</property>
1093+ <property name="label" translatable="yes">help label</property>
1094+ <property name="wrap">True</property>
1095+ </object>
1096+ <packing>
1097+ <property name="expand">False</property>
1098+ <property name="fill">True</property>
1099+ <property name="position">1</property>
1100+ </packing>
1101+ </child>
1102+ <child>
1103+ <object class="GtkLabel" id="warning_label">
1104+ <property name="visible">True</property>
1105+ <property name="can_focus">False</property>
1106+ <property name="xalign">0</property>
1107+ <property name="label" translatable="yes">warning label</property>
1108+ <property name="wrap">True</property>
1109+ </object>
1110+ <packing>
1111+ <property name="expand">False</property>
1112+ <property name="fill">True</property>
1113+ <property name="position">2</property>
1114+ </packing>
1115+ </child>
1116+ <child>
1117+ <object class="GtkNotebook" id="content">
1118+ <property name="visible">True</property>
1119+ <property name="can_focus">True</property>
1120+ <property name="show_tabs">False</property>
1121+ <property name="show_border">False</property>
1122+ </object>
1123+ <packing>
1124+ <property name="expand">True</property>
1125+ <property name="fill">True</property>
1126+ <property name="position">3</property>
1127+ </packing>
1128+ </child>
1129+ </object>
1130+ </child>
1131+ </object>
1132 </interface>
1133
1134=== modified file 'data/qt/choose_sign_in.ui'
1135--- data/qt/choose_sign_in.ui 2011-04-05 14:04:50 +0000
1136+++ data/qt/choose_sign_in.ui 2012-02-14 22:04:20 +0000
1137@@ -1,32 +1,103 @@
1138 <?xml version="1.0" encoding="UTF-8"?>
1139 <ui version="4.0">
1140 <class>ChooseSignInPage</class>
1141- <widget class="QWizardPage" name="ChooseSingInPage">
1142+ <widget class="QWizardPage" name="ChooseSignInPage">
1143 <property name="geometry">
1144 <rect>
1145 <x>0</x>
1146 <y>0</y>
1147- <width>400</width>
1148- <height>300</height>
1149+ <width>432</width>
1150+ <height>387</height>
1151 </rect>
1152 </property>
1153 <property name="windowTitle">
1154 <string>WizardPage</string>
1155 </property>
1156- <layout class="QHBoxLayout" name="horizontalLayout">
1157- <item>
1158- <layout class="QHBoxLayout" name="horizontalLayout_3">
1159+ <layout class="QVBoxLayout" name="verticalLayout_2">
1160+ <property name="leftMargin">
1161+ <number>0</number>
1162+ </property>
1163+ <property name="topMargin">
1164+ <number>0</number>
1165+ </property>
1166+ <property name="rightMargin">
1167+ <number>0</number>
1168+ </property>
1169+ <item>
1170+ <layout class="QHBoxLayout" name="horizontalLayout_2">
1171+ <item>
1172+ <widget class="QLabel" name="image_label">
1173+ <property name="sizePolicy">
1174+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1175+ <horstretch>0</horstretch>
1176+ <verstretch>0</verstretch>
1177+ </sizepolicy>
1178+ </property>
1179+ <property name="minimumSize">
1180+ <size>
1181+ <width>400</width>
1182+ <height>150</height>
1183+ </size>
1184+ </property>
1185+ <property name="text">
1186+ <string/>
1187+ </property>
1188+ <property name="textFormat">
1189+ <enum>Qt::PlainText</enum>
1190+ </property>
1191+ <property name="alignment">
1192+ <set>Qt::AlignCenter</set>
1193+ </property>
1194+ <property name="wordWrap">
1195+ <bool>true</bool>
1196+ </property>
1197+ </widget>
1198+ </item>
1199+ </layout>
1200+ </item>
1201+ <item>
1202+ <widget class="QLabel" name="message_label">
1203+ <property name="font">
1204+ <font>
1205+ <pointsize>11</pointsize>
1206+ <weight>50</weight>
1207+ <bold>false</bold>
1208+ </font>
1209+ </property>
1210+ <property name="text">
1211+ <string>Congratulations, app_name is installed!</string>
1212+ </property>
1213+ <property name="alignment">
1214+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
1215+ </property>
1216+ </widget>
1217+ </item>
1218+ <item>
1219+ <spacer name="verticalSpacer_3">
1220+ <property name="orientation">
1221+ <enum>Qt::Vertical</enum>
1222+ </property>
1223+ <property name="sizeType">
1224+ <enum>QSizePolicy::Fixed</enum>
1225+ </property>
1226+ <property name="sizeHint" stdset="0">
1227+ <size>
1228+ <width>20</width>
1229+ <height>30</height>
1230+ </size>
1231+ </property>
1232+ </spacer>
1233+ </item>
1234+ <item>
1235+ <layout class="QHBoxLayout" name="horizontalLayout">
1236 <item>
1237 <spacer name="horizontalSpacer_2">
1238 <property name="orientation">
1239 <enum>Qt::Horizontal</enum>
1240 </property>
1241- <property name="sizeType">
1242- <enum>QSizePolicy::Expanding</enum>
1243- </property>
1244 <property name="sizeHint" stdset="0">
1245 <size>
1246- <width>40</width>
1247+ <width>20</width>
1248 <height>20</height>
1249 </size>
1250 </property>
1251@@ -35,44 +106,11 @@
1252 <item>
1253 <layout class="QVBoxLayout" name="verticalLayout">
1254 <item>
1255- <spacer name="verticalSpacer_3">
1256- <property name="orientation">
1257- <enum>Qt::Vertical</enum>
1258- </property>
1259- <property name="sizeHint" stdset="0">
1260- <size>
1261- <width>20</width>
1262- <height>40</height>
1263- </size>
1264- </property>
1265- </spacer>
1266- </item>
1267- <item>
1268- <layout class="QHBoxLayout" name="horizontalLayout_2">
1269- <item>
1270- <widget class="QPushButton" name="existing_account_button">
1271- <property name="text">
1272- <string/>
1273- </property>
1274- </widget>
1275- </item>
1276- </layout>
1277- </item>
1278- <item>
1279- <spacer name="verticalSpacer">
1280- <property name="orientation">
1281- <enum>Qt::Vertical</enum>
1282- </property>
1283- <property name="sizeType">
1284- <enum>QSizePolicy::Fixed</enum>
1285- </property>
1286- <property name="sizeHint" stdset="0">
1287- <size>
1288- <width>20</width>
1289- <height>10</height>
1290- </size>
1291- </property>
1292- </spacer>
1293+ <widget class="QPushButton" name="existing_account_button">
1294+ <property name="text">
1295+ <string/>
1296+ </property>
1297+ </widget>
1298 </item>
1299 <item>
1300 <widget class="QPushButton" name="setup_account_button">
1301@@ -82,17 +120,11 @@
1302 </widget>
1303 </item>
1304 <item>
1305- <spacer name="verticalSpacer_2">
1306- <property name="orientation">
1307- <enum>Qt::Vertical</enum>
1308- </property>
1309- <property name="sizeHint" stdset="0">
1310- <size>
1311- <width>20</width>
1312- <height>40</height>
1313- </size>
1314- </property>
1315- </spacer>
1316+ <widget class="QPushButton" name="cancel_button">
1317+ <property name="text">
1318+ <string/>
1319+ </property>
1320+ </widget>
1321 </item>
1322 </layout>
1323 </item>
1324@@ -106,7 +138,7 @@
1325 </property>
1326 <property name="sizeHint" stdset="0">
1327 <size>
1328- <width>40</width>
1329+ <width>20</width>
1330 <height>20</height>
1331 </size>
1332 </property>
1333@@ -114,8 +146,20 @@
1334 </item>
1335 </layout>
1336 </item>
1337+ <item>
1338+ <spacer name="verticalSpacer_2">
1339+ <property name="orientation">
1340+ <enum>Qt::Vertical</enum>
1341+ </property>
1342+ <property name="sizeHint" stdset="0">
1343+ <size>
1344+ <width>20</width>
1345+ <height>50</height>
1346+ </size>
1347+ </property>
1348+ </spacer>
1349+ </item>
1350 </layout>
1351 </widget>
1352- <resources/>
1353 <connections/>
1354 </ui>
1355
1356=== added file 'data/qt/loadingoverlay.ui'
1357--- data/qt/loadingoverlay.ui 1970-01-01 00:00:00 +0000
1358+++ data/qt/loadingoverlay.ui 2012-02-14 22:04:20 +0000
1359@@ -0,0 +1,103 @@
1360+<?xml version="1.0" encoding="UTF-8"?>
1361+<ui version="4.0">
1362+ <class>Form</class>
1363+ <widget class="QFrame" name="Form">
1364+ <property name="geometry">
1365+ <rect>
1366+ <x>0</x>
1367+ <y>0</y>
1368+ <width>702</width>
1369+ <height>230</height>
1370+ </rect>
1371+ </property>
1372+ <property name="windowTitle">
1373+ <string>Frame</string>
1374+ </property>
1375+ <layout class="QVBoxLayout" name="verticalLayout">
1376+ <property name="topMargin">
1377+ <number>30</number>
1378+ </property>
1379+ <item>
1380+ <layout class="QHBoxLayout" name="horizontalLayout_2">
1381+ <item>
1382+ <spacer name="horizontalSpacer_2">
1383+ <property name="orientation">
1384+ <enum>Qt::Horizontal</enum>
1385+ </property>
1386+ <property name="sizeHint" stdset="0">
1387+ <size>
1388+ <width>40</width>
1389+ <height>20</height>
1390+ </size>
1391+ </property>
1392+ </spacer>
1393+ </item>
1394+ <item>
1395+ <widget class="QFrame" name="frm_box">
1396+ <property name="minimumSize">
1397+ <size>
1398+ <width>0</width>
1399+ <height>102</height>
1400+ </size>
1401+ </property>
1402+ <layout class="QHBoxLayout" name="horizontalLayout">
1403+ <property name="topMargin">
1404+ <number>0</number>
1405+ </property>
1406+ <property name="bottomMargin">
1407+ <number>30</number>
1408+ </property>
1409+ <item>
1410+ <widget class="QLabel" name="label">
1411+ <property name="sizePolicy">
1412+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1413+ <horstretch>0</horstretch>
1414+ <verstretch>0</verstretch>
1415+ </sizepolicy>
1416+ </property>
1417+ <property name="font">
1418+ <font>
1419+ <pointsize>14</pointsize>
1420+ </font>
1421+ </property>
1422+ <property name="text">
1423+ <string>Getting information, please wait...</string>
1424+ </property>
1425+ </widget>
1426+ </item>
1427+ </layout>
1428+ </widget>
1429+ </item>
1430+ <item>
1431+ <spacer name="horizontalSpacer">
1432+ <property name="orientation">
1433+ <enum>Qt::Horizontal</enum>
1434+ </property>
1435+ <property name="sizeHint" stdset="0">
1436+ <size>
1437+ <width>40</width>
1438+ <height>20</height>
1439+ </size>
1440+ </property>
1441+ </spacer>
1442+ </item>
1443+ </layout>
1444+ </item>
1445+ <item>
1446+ <spacer name="verticalSpacer">
1447+ <property name="orientation">
1448+ <enum>Qt::Vertical</enum>
1449+ </property>
1450+ <property name="sizeHint" stdset="0">
1451+ <size>
1452+ <width>20</width>
1453+ <height>20</height>
1454+ </size>
1455+ </property>
1456+ </spacer>
1457+ </item>
1458+ </layout>
1459+ </widget>
1460+ <resources/>
1461+ <connections/>
1462+</ui>
1463
1464=== added file 'data/qt/network_detection.ui'
1465--- data/qt/network_detection.ui 1970-01-01 00:00:00 +0000
1466+++ data/qt/network_detection.ui 2012-02-14 22:04:20 +0000
1467@@ -0,0 +1,142 @@
1468+<?xml version="1.0" encoding="UTF-8"?>
1469+<ui version="4.0">
1470+ <class>Form</class>
1471+ <widget class="QWizardPage" name="Form">
1472+ <property name="geometry">
1473+ <rect>
1474+ <x>0</x>
1475+ <y>0</y>
1476+ <width>541</width>
1477+ <height>365</height>
1478+ </rect>
1479+ </property>
1480+ <property name="windowTitle">
1481+ <string>WizardPage</string>
1482+ </property>
1483+ <layout class="QVBoxLayout" name="verticalLayout">
1484+ <item>
1485+ <layout class="QHBoxLayout" name="horizontalLayout_2">
1486+ <item>
1487+ <spacer name="horizontalSpacer_3">
1488+ <property name="orientation">
1489+ <enum>Qt::Horizontal</enum>
1490+ </property>
1491+ <property name="sizeHint" stdset="0">
1492+ <size>
1493+ <width>40</width>
1494+ <height>20</height>
1495+ </size>
1496+ </property>
1497+ </spacer>
1498+ </item>
1499+ <item>
1500+ <widget class="QLabel" name="image_label">
1501+ <property name="sizePolicy">
1502+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1503+ <horstretch>0</horstretch>
1504+ <verstretch>0</verstretch>
1505+ </sizepolicy>
1506+ </property>
1507+ <property name="minimumSize">
1508+ <size>
1509+ <width>400</width>
1510+ <height>150</height>
1511+ </size>
1512+ </property>
1513+ <property name="text">
1514+ <string/>
1515+ </property>
1516+ <property name="textFormat">
1517+ <enum>Qt::PlainText</enum>
1518+ </property>
1519+ <property name="alignment">
1520+ <set>Qt::AlignCenter</set>
1521+ </property>
1522+ <property name="wordWrap">
1523+ <bool>true</bool>
1524+ </property>
1525+ </widget>
1526+ </item>
1527+ <item>
1528+ <spacer name="horizontalSpacer_4">
1529+ <property name="orientation">
1530+ <enum>Qt::Horizontal</enum>
1531+ </property>
1532+ <property name="sizeHint" stdset="0">
1533+ <size>
1534+ <width>40</width>
1535+ <height>20</height>
1536+ </size>
1537+ </property>
1538+ </spacer>
1539+ </item>
1540+ </layout>
1541+ </item>
1542+ <item>
1543+ <widget class="QLabel" name="message_label">
1544+ <property name="alignment">
1545+ <set>Qt::AlignCenter</set>
1546+ </property>
1547+ </widget>
1548+ </item>
1549+ <item>
1550+ <layout class="QHBoxLayout" name="horizontalLayout">
1551+ <item>
1552+ <spacer name="horizontalSpacer">
1553+ <property name="orientation">
1554+ <enum>Qt::Horizontal</enum>
1555+ </property>
1556+ <property name="sizeHint" stdset="0">
1557+ <size>
1558+ <width>40</width>
1559+ <height>20</height>
1560+ </size>
1561+ </property>
1562+ </spacer>
1563+ </item>
1564+ <item>
1565+ <widget class="QLabel" name="label">
1566+ <property name="text">
1567+ <string>Are you online? We can't detect an internet connection - you will need to be connected to set up Ubuntu Single Sign On</string>
1568+ </property>
1569+ <property name="textFormat">
1570+ <enum>Qt::PlainText</enum>
1571+ </property>
1572+ <property name="wordWrap">
1573+ <bool>true</bool>
1574+ </property>
1575+ </widget>
1576+ </item>
1577+ <item>
1578+ <spacer name="horizontalSpacer_2">
1579+ <property name="orientation">
1580+ <enum>Qt::Horizontal</enum>
1581+ </property>
1582+ <property name="sizeHint" stdset="0">
1583+ <size>
1584+ <width>40</width>
1585+ <height>20</height>
1586+ </size>
1587+ </property>
1588+ </spacer>
1589+ </item>
1590+ </layout>
1591+ </item>
1592+ <item>
1593+ <spacer name="verticalSpacer">
1594+ <property name="orientation">
1595+ <enum>Qt::Vertical</enum>
1596+ </property>
1597+ <property name="sizeHint" stdset="0">
1598+ <size>
1599+ <width>20</width>
1600+ <height>76</height>
1601+ </size>
1602+ </property>
1603+ </spacer>
1604+ </item>
1605+ </layout>
1606+ </widget>
1607+ <resources/>
1608+ <connections/>
1609+</ui>
1610
1611=== added file 'data/qt/proxy_credentials_dialog.ui'
1612--- data/qt/proxy_credentials_dialog.ui 1970-01-01 00:00:00 +0000
1613+++ data/qt/proxy_credentials_dialog.ui 2012-02-14 22:04:20 +0000
1614@@ -0,0 +1,316 @@
1615+<?xml version="1.0" encoding="UTF-8"?>
1616+<ui version="4.0">
1617+ <class>ProxyCredsDialog</class>
1618+ <widget class="QDialog" name="ProxyCredsDialog">
1619+ <property name="windowModality">
1620+ <enum>Qt::NonModal</enum>
1621+ </property>
1622+ <property name="geometry">
1623+ <rect>
1624+ <x>0</x>
1625+ <y>0</y>
1626+ <width>550</width>
1627+ <height>364</height>
1628+ </rect>
1629+ </property>
1630+ <property name="sizePolicy">
1631+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1632+ <horstretch>0</horstretch>
1633+ <verstretch>0</verstretch>
1634+ </sizepolicy>
1635+ </property>
1636+ <property name="minimumSize">
1637+ <size>
1638+ <width>502</width>
1639+ <height>0</height>
1640+ </size>
1641+ </property>
1642+ <property name="windowTitle">
1643+ <string>Add proxy settings</string>
1644+ </property>
1645+ <property name="sizeGripEnabled">
1646+ <bool>false</bool>
1647+ </property>
1648+ <layout class="QHBoxLayout" name="horizontalLayout">
1649+ <property name="sizeConstraint">
1650+ <enum>QLayout::SetFixedSize</enum>
1651+ </property>
1652+ <item>
1653+ <layout class="QVBoxLayout" name="verticalLayout">
1654+ <property name="spacing">
1655+ <number>24</number>
1656+ </property>
1657+ <item>
1658+ <layout class="QHBoxLayout" name="horizontalLayout_4">
1659+ <property name="spacing">
1660+ <number>12</number>
1661+ </property>
1662+ <item>
1663+ <layout class="QVBoxLayout" name="verticalLayout_4">
1664+ <property name="spacing">
1665+ <number>0</number>
1666+ </property>
1667+ <property name="sizeConstraint">
1668+ <enum>QLayout::SetDefaultConstraint</enum>
1669+ </property>
1670+ <item>
1671+ <widget class="QLabel" name="logo_label">
1672+ <property name="sizePolicy">
1673+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
1674+ <horstretch>0</horstretch>
1675+ <verstretch>0</verstretch>
1676+ </sizepolicy>
1677+ </property>
1678+ <property name="minimumSize">
1679+ <size>
1680+ <width>48</width>
1681+ <height>48</height>
1682+ </size>
1683+ </property>
1684+ <property name="maximumSize">
1685+ <size>
1686+ <width>48</width>
1687+ <height>48</height>
1688+ </size>
1689+ </property>
1690+ <property name="text">
1691+ <string>TextLabel</string>
1692+ </property>
1693+ </widget>
1694+ </item>
1695+ <item>
1696+ <spacer name="verticalSpacer_4">
1697+ <property name="orientation">
1698+ <enum>Qt::Vertical</enum>
1699+ </property>
1700+ <property name="sizeType">
1701+ <enum>QSizePolicy::Expanding</enum>
1702+ </property>
1703+ <property name="sizeHint" stdset="0">
1704+ <size>
1705+ <width>0</width>
1706+ <height>20</height>
1707+ </size>
1708+ </property>
1709+ </spacer>
1710+ </item>
1711+ </layout>
1712+ </item>
1713+ <item>
1714+ <layout class="QVBoxLayout" name="verticalLayout_3">
1715+ <property name="spacing">
1716+ <number>24</number>
1717+ </property>
1718+ <item>
1719+ <layout class="QVBoxLayout" name="verticalLayout_2">
1720+ <property name="spacing">
1721+ <number>24</number>
1722+ </property>
1723+ <item>
1724+ <widget class="QLabel" name="title_label">
1725+ <property name="sizePolicy">
1726+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
1727+ <horstretch>0</horstretch>
1728+ <verstretch>0</verstretch>
1729+ </sizepolicy>
1730+ </property>
1731+ <property name="font">
1732+ <font>
1733+ <pointsize>14</pointsize>
1734+ <weight>75</weight>
1735+ <bold>true</bold>
1736+ </font>
1737+ </property>
1738+ <property name="text">
1739+ <string>You are connection through a proxy.</string>
1740+ </property>
1741+ <property name="wordWrap">
1742+ <bool>true</bool>
1743+ </property>
1744+ </widget>
1745+ </item>
1746+ <item>
1747+ <widget class="QLabel" name="explanation_label">
1748+ <property name="text">
1749+ <string>Please provide the login details below, or check your system settings</string>
1750+ </property>
1751+ <property name="wordWrap">
1752+ <bool>true</bool>
1753+ </property>
1754+ </widget>
1755+ </item>
1756+ </layout>
1757+ </item>
1758+ <item>
1759+ <widget class="QFrame" name="frame">
1760+ <property name="frameShape">
1761+ <enum>QFrame::NoFrame</enum>
1762+ </property>
1763+ <property name="frameShadow">
1764+ <enum>QFrame::Plain</enum>
1765+ </property>
1766+ <layout class="QGridLayout" name="gridLayout_2">
1767+ <property name="spacing">
1768+ <number>12</number>
1769+ </property>
1770+ <item row="0" column="0">
1771+ <widget class="QLabel" name="connection_label">
1772+ <property name="sizePolicy">
1773+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
1774+ <horstretch>0</horstretch>
1775+ <verstretch>0</verstretch>
1776+ </sizepolicy>
1777+ </property>
1778+ <property name="text">
1779+ <string>Connecting to:</string>
1780+ </property>
1781+ <property name="alignment">
1782+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
1783+ </property>
1784+ </widget>
1785+ </item>
1786+ <item row="0" column="1">
1787+ <widget class="QLabel" name="domain_label">
1788+ <property name="text">
1789+ <string/>
1790+ </property>
1791+ </widget>
1792+ </item>
1793+ <item row="4" column="0">
1794+ <widget class="QLabel" name="username_label">
1795+ <property name="text">
1796+ <string>Proxy username:</string>
1797+ </property>
1798+ <property name="alignment">
1799+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
1800+ </property>
1801+ </widget>
1802+ </item>
1803+ <item row="4" column="1">
1804+ <widget class="QLineEdit" name="username_entry">
1805+ <property name="text">
1806+ <string/>
1807+ </property>
1808+ </widget>
1809+ </item>
1810+ <item row="5" column="0">
1811+ <widget class="QLabel" name="password_label">
1812+ <property name="text">
1813+ <string>Proxy password:</string>
1814+ </property>
1815+ <property name="alignment">
1816+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
1817+ </property>
1818+ </widget>
1819+ </item>
1820+ <item row="5" column="1">
1821+ <widget class="QLineEdit" name="password_entry">
1822+ <property name="echoMode">
1823+ <enum>QLineEdit::Password</enum>
1824+ </property>
1825+ </widget>
1826+ </item>
1827+ <item row="1" column="0">
1828+ <spacer name="verticalSpacer">
1829+ <property name="orientation">
1830+ <enum>Qt::Vertical</enum>
1831+ </property>
1832+ <property name="sizeType">
1833+ <enum>QSizePolicy::Fixed</enum>
1834+ </property>
1835+ <property name="sizeHint" stdset="0">
1836+ <size>
1837+ <width>24</width>
1838+ <height>12</height>
1839+ </size>
1840+ </property>
1841+ </spacer>
1842+ </item>
1843+ <item row="2" column="0" colspan="2">
1844+ <widget class="QLabel" name="error_label">
1845+ <property name="text">
1846+ <string>TextLabel</string>
1847+ </property>
1848+ <property name="wordWrap">
1849+ <bool>false</bool>
1850+ </property>
1851+ </widget>
1852+ </item>
1853+ <item row="3" column="0">
1854+ <spacer name="verticalSpacer_2">
1855+ <property name="orientation">
1856+ <enum>Qt::Vertical</enum>
1857+ </property>
1858+ <property name="sizeType">
1859+ <enum>QSizePolicy::Fixed</enum>
1860+ </property>
1861+ <property name="sizeHint" stdset="0">
1862+ <size>
1863+ <width>24</width>
1864+ <height>12</height>
1865+ </size>
1866+ </property>
1867+ </spacer>
1868+ </item>
1869+ </layout>
1870+ </widget>
1871+ </item>
1872+ </layout>
1873+ </item>
1874+ </layout>
1875+ </item>
1876+ <item>
1877+ <layout class="QHBoxLayout" name="horizontalLayout_5">
1878+ <item>
1879+ <widget class="QPushButton" name="help_button">
1880+ <property name="text">
1881+ <string>Get Help With Proxies</string>
1882+ </property>
1883+ </widget>
1884+ </item>
1885+ <item>
1886+ <spacer name="horizontalSpacer">
1887+ <property name="orientation">
1888+ <enum>Qt::Horizontal</enum>
1889+ </property>
1890+ <property name="sizeHint" stdset="0">
1891+ <size>
1892+ <width>40</width>
1893+ <height>20</height>
1894+ </size>
1895+ </property>
1896+ </spacer>
1897+ </item>
1898+ <item>
1899+ <widget class="QPushButton" name="cancel_button">
1900+ <property name="text">
1901+ <string>Cancel and Close</string>
1902+ </property>
1903+ </widget>
1904+ </item>
1905+ <item>
1906+ <widget class="QPushButton" name="save_button">
1907+ <property name="text">
1908+ <string>Save</string>
1909+ </property>
1910+ <property name="default">
1911+ <bool>true</bool>
1912+ </property>
1913+ </widget>
1914+ </item>
1915+ </layout>
1916+ </item>
1917+ </layout>
1918+ </item>
1919+ </layout>
1920+ </widget>
1921+ <tabstops>
1922+ <tabstop>username_entry</tabstop>
1923+ <tabstop>password_entry</tabstop>
1924+ <tabstop>save_button</tabstop>
1925+ <tabstop>cancel_button</tabstop>
1926+ <tabstop>help_button</tabstop>
1927+ </tabstops>
1928+ <resources/>
1929+ <connections/>
1930+</ui>
1931
1932=== modified file 'data/qt/setup_account.ui'
1933--- data/qt/setup_account.ui 2011-09-02 12:53:55 +0000
1934+++ data/qt/setup_account.ui 2012-02-14 22:04:20 +0000
1935@@ -6,275 +6,662 @@
1936 <rect>
1937 <x>0</x>
1938 <y>0</y>
1939- <width>407</width>
1940- <height>572</height>
1941+ <width>543</width>
1942+ <height>523</height>
1943 </rect>
1944 </property>
1945+ <property name="sizePolicy">
1946+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
1947+ <horstretch>0</horstretch>
1948+ <verstretch>0</verstretch>
1949+ </sizepolicy>
1950+ </property>
1951+ <property name="maximumSize">
1952+ <size>
1953+ <width>16777215</width>
1954+ <height>16777215</height>
1955+ </size>
1956+ </property>
1957 <property name="windowTitle">
1958 <string>WizardPage</string>
1959 </property>
1960- <layout class="QVBoxLayout" name="verticalLayout_5">
1961+ <layout class="QVBoxLayout" name="verticalLayout">
1962+ <property name="spacing">
1963+ <number>0</number>
1964+ </property>
1965+ <property name="leftMargin">
1966+ <number>0</number>
1967+ </property>
1968 <property name="topMargin">
1969 <number>0</number>
1970 </property>
1971+ <property name="rightMargin">
1972+ <number>3</number>
1973+ </property>
1974+ <property name="bottomMargin">
1975+ <number>0</number>
1976+ </property>
1977 <item>
1978- <layout class="QVBoxLayout" name="verticalLayout">
1979- <item>
1980- <widget class="QFrame" name="_signInFrame">
1981- <property name="frameShape">
1982- <enum>QFrame::NoFrame</enum>
1983- </property>
1984- <layout class="QVBoxLayout" name="verticalLayout_3">
1985- <item>
1986- <layout class="QVBoxLayout" name="verticalLayout_2">
1987- <item>
1988- <widget class="QLabel" name="password_info_label">
1989- <property name="sizePolicy">
1990- <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
1991- <horstretch>0</horstretch>
1992- <verstretch>0</verstretch>
1993- </sizepolicy>
1994- </property>
1995- <property name="text">
1996- <string/>
1997- </property>
1998- <property name="wordWrap">
1999- <bool>true</bool>
2000- </property>
2001- </widget>
2002- </item>
2003- <item>
2004- <layout class="QVBoxLayout" name="verticalLayout_4">
2005- <item>
2006- <widget class="QLabel" name="name_label">
2007- <property name="text">
2008- <string/>
2009- </property>
2010- </widget>
2011- </item>
2012- <item>
2013- <widget class="QLineEdit" name="name_edit">
2014- <property name="placeholderText">
2015- <string/>
2016- </property>
2017- </widget>
2018- </item>
2019- <item>
2020- <widget class="QLabel" name="email_label">
2021- <property name="text">
2022- <string/>
2023- </property>
2024- </widget>
2025- </item>
2026- <item>
2027- <widget class="QLineEdit" name="email_edit">
2028- <property name="placeholderText">
2029- <string/>
2030- </property>
2031- </widget>
2032- </item>
2033- <item>
2034- <widget class="QLabel" name="confirm_email_label">
2035- <property name="text">
2036- <string/>
2037- </property>
2038- </widget>
2039- </item>
2040- <item>
2041- <widget class="QLineEdit" name="confirm_email_edit">
2042- <property name="placeholderText">
2043- <string/>
2044- </property>
2045- </widget>
2046- </item>
2047- <item>
2048- <widget class="QLabel" name="password_label">
2049- <property name="text">
2050- <string/>
2051- </property>
2052- </widget>
2053- </item>
2054- <item>
2055- <widget class="QLineEdit" name="password_edit">
2056- <property name="toolTip">
2057- <string>Your password must be at least 8 characters long and at least contain one number and one upper later.</string>
2058- </property>
2059- <property name="statusTip">
2060- <string/>
2061- </property>
2062- <property name="echoMode">
2063- <enum>QLineEdit::Password</enum>
2064- </property>
2065- <property name="placeholderText">
2066- <string/>
2067- </property>
2068- </widget>
2069- </item>
2070- <item>
2071- <widget class="QLabel" name="confirm_password_label">
2072- <property name="text">
2073- <string/>
2074- </property>
2075- </widget>
2076- </item>
2077- <item>
2078- <widget class="QLineEdit" name="confirm_password_edit">
2079- <property name="echoMode">
2080- <enum>QLineEdit::Password</enum>
2081- </property>
2082- <property name="placeholderText">
2083- <string/>
2084- </property>
2085- </widget>
2086- </item>
2087- </layout>
2088- </item>
2089- <item>
2090- <layout class="QVBoxLayout" name="verticalLayout_9">
2091- <item>
2092- <widget class="QFrame" name="frame_2">
2093- <property name="sizePolicy">
2094- <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
2095- <horstretch>0</horstretch>
2096- <verstretch>0</verstretch>
2097- </sizepolicy>
2098- </property>
2099- <property name="frameShape">
2100- <enum>QFrame::StyledPanel</enum>
2101- </property>
2102- <property name="frameShadow">
2103- <enum>QFrame::Raised</enum>
2104- </property>
2105- <layout class="QHBoxLayout" name="horizontalLayout_16">
2106- <property name="leftMargin">
2107- <number>0</number>
2108- </property>
2109- <item>
2110- <widget class="QLabel" name="captcha_view">
2111- <property name="minimumSize">
2112- <size>
2113- <width>0</width>
2114- <height>57</height>
2115- </size>
2116- </property>
2117- <property name="frameShape">
2118- <enum>QFrame::Box</enum>
2119- </property>
2120- <property name="text">
2121- <string/>
2122- </property>
2123- </widget>
2124- </item>
2125- <item>
2126- <widget class="QLabel" name="refresh_label">
2127- <property name="sizePolicy">
2128- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
2129- <horstretch>0</horstretch>
2130- <verstretch>0</verstretch>
2131- </sizepolicy>
2132- </property>
2133- <property name="locale">
2134- <locale language="English" country="UnitedStates"/>
2135- </property>
2136- <property name="text">
2137- <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
2138-&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
2139-p, li { white-space: pre-wrap; }
2140-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
2141-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;If you can't read this then &lt;/span&gt;&lt;a href=&quot;example.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;refresh&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; this page&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
2142- </property>
2143- <property name="wordWrap">
2144- <bool>true</bool>
2145- </property>
2146- </widget>
2147- </item>
2148- </layout>
2149- </widget>
2150- </item>
2151- <item>
2152- <widget class="QLineEdit" name="captcha_solution_edit">
2153- <property name="locale">
2154- <locale language="English" country="UnitedStates"/>
2155- </property>
2156- <property name="inputMask">
2157- <string/>
2158- </property>
2159- <property name="text">
2160- <string/>
2161- </property>
2162- <property name="placeholderText">
2163- <string/>
2164- </property>
2165- </widget>
2166- </item>
2167- </layout>
2168- </item>
2169- <item>
2170- <widget class="QCheckBox" name="terms_checkbox">
2171- <property name="text">
2172- <string/>
2173- </property>
2174- </widget>
2175- </item>
2176- <item>
2177- <layout class="QHBoxLayout" name="horizontalLayout_4">
2178- <property name="spacing">
2179- <number>0</number>
2180- </property>
2181- <item>
2182- <widget class="QPushButton" name="terms_button">
2183- <property name="text">
2184- <string/>
2185- </property>
2186- </widget>
2187- </item>
2188- <item>
2189- <spacer name="horizontalSpacer_3">
2190- <property name="orientation">
2191- <enum>Qt::Horizontal</enum>
2192- </property>
2193- <property name="sizeHint" stdset="0">
2194- <size>
2195- <width>40</width>
2196- <height>20</height>
2197- </size>
2198- </property>
2199- </spacer>
2200- </item>
2201- <item>
2202- <widget class="QPushButton" name="set_up_button">
2203- <property name="enabled">
2204- <bool>false</bool>
2205- </property>
2206- <property name="text">
2207- <string/>
2208- </property>
2209- </widget>
2210- </item>
2211- </layout>
2212- </item>
2213- </layout>
2214- </item>
2215- </layout>
2216- </widget>
2217- </item>
2218- <item>
2219+ <layout class="QGridLayout" name="gridLayout" columnminimumwidth="310,220">
2220+ <item row="0" column="0">
2221+ <widget class="QLabel" name="password_info_label">
2222+ <property name="sizePolicy">
2223+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
2224+ <horstretch>0</horstretch>
2225+ <verstretch>0</verstretch>
2226+ </sizepolicy>
2227+ </property>
2228+ <property name="text">
2229+ <string>If you can't read this then &lt;a href=&quot;example.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#dd4814;&quot;&gt;refresh&lt;/span&gt;&lt;/a&gt; this page&lt;/span&gt;</string>
2230+ </property>
2231+ <property name="wordWrap">
2232+ <bool>true</bool>
2233+ </property>
2234+ </widget>
2235+ </item>
2236+ <item row="1" column="0">
2237+ <layout class="QVBoxLayout" name="verticalLayout">
2238+ <property name="spacing">
2239+ <number>3</number>
2240+ </property>
2241+ <item>
2242+ <widget class="QLabel" name="name_label">
2243+ <property name="font">
2244+ <font>
2245+ <weight>75</weight>
2246+ <bold>true</bold>
2247+ </font>
2248+ </property>
2249+ <property name="text">
2250+ <string>name_label</string>
2251+ </property>
2252+ </widget>
2253+ </item>
2254+ <item>
2255+ <widget class="QLineEdit" name="name_edit">
2256+ <property name="sizePolicy">
2257+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
2258+ <horstretch>0</horstretch>
2259+ <verstretch>0</verstretch>
2260+ </sizepolicy>
2261+ </property>
2262+ <property name="minimumSize">
2263+ <size>
2264+ <width>300</width>
2265+ <height>0</height>
2266+ </size>
2267+ </property>
2268+ <property name="maximumSize">
2269+ <size>
2270+ <width>300</width>
2271+ <height>16777215</height>
2272+ </size>
2273+ </property>
2274+ <property name="font">
2275+ <font>
2276+ <pointsize>11</pointsize>
2277+ </font>
2278+ </property>
2279+ <property name="formError" stdset="0">
2280+ <bool>false</bool>
2281+ </property>
2282+ </widget>
2283+ </item>
2284+ </layout>
2285+ </item>
2286+ <item row="3" column="0">
2287+ <layout class="QVBoxLayout" name="verticalLayout">
2288+ <property name="spacing">
2289+ <number>3</number>
2290+ </property>
2291+ <item>
2292+ <widget class="QLabel" name="email_label">
2293+ <property name="font">
2294+ <font>
2295+ <weight>75</weight>
2296+ <bold>true</bold>
2297+ </font>
2298+ </property>
2299+ <property name="text">
2300+ <string>email_label</string>
2301+ </property>
2302+ </widget>
2303+ </item>
2304+ <item>
2305+ <widget class="QLineEdit" name="email_edit">
2306+ <property name="sizePolicy">
2307+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
2308+ <horstretch>0</horstretch>
2309+ <verstretch>0</verstretch>
2310+ </sizepolicy>
2311+ </property>
2312+ <property name="minimumSize">
2313+ <size>
2314+ <width>300</width>
2315+ <height>0</height>
2316+ </size>
2317+ </property>
2318+ <property name="maximumSize">
2319+ <size>
2320+ <width>300</width>
2321+ <height>16777215</height>
2322+ </size>
2323+ </property>
2324+ <property name="font">
2325+ <font>
2326+ <pointsize>11</pointsize>
2327+ </font>
2328+ </property>
2329+ <property name="placeholderText">
2330+ <string/>
2331+ </property>
2332+ <property name="formError" stdset="0">
2333+ <bool>false</bool>
2334+ </property>
2335+ </widget>
2336+ </item>
2337+ </layout>
2338+ </item>
2339+ <item row="4" column="0">
2340+ <layout class="QVBoxLayout" name="verticalLayout">
2341+ <property name="spacing">
2342+ <number>3</number>
2343+ </property>
2344+ <item>
2345+ <widget class="QLabel" name="confirm_email_label">
2346+ <property name="font">
2347+ <font>
2348+ <weight>75</weight>
2349+ <bold>true</bold>
2350+ </font>
2351+ </property>
2352+ <property name="text">
2353+ <string>confirm_email_label</string>
2354+ </property>
2355+ </widget>
2356+ </item>
2357+ <item>
2358+ <widget class="QLineEdit" name="confirm_email_edit">
2359+ <property name="sizePolicy">
2360+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
2361+ <horstretch>0</horstretch>
2362+ <verstretch>0</verstretch>
2363+ </sizepolicy>
2364+ </property>
2365+ <property name="minimumSize">
2366+ <size>
2367+ <width>300</width>
2368+ <height>0</height>
2369+ </size>
2370+ </property>
2371+ <property name="maximumSize">
2372+ <size>
2373+ <width>300</width>
2374+ <height>16777215</height>
2375+ </size>
2376+ </property>
2377+ <property name="font">
2378+ <font>
2379+ <pointsize>11</pointsize>
2380+ </font>
2381+ </property>
2382+ <property name="placeholderText">
2383+ <string/>
2384+ </property>
2385+ <property name="formError" stdset="0">
2386+ <bool>false</bool>
2387+ </property>
2388+ </widget>
2389+ </item>
2390+ </layout>
2391+ </item>
2392+ <item row="6" column="0">
2393+ <layout class="QVBoxLayout" name="verticalLayout">
2394+ <property name="spacing">
2395+ <number>3</number>
2396+ </property>
2397+ <item>
2398+ <widget class="QLabel" name="password_label">
2399+ <property name="font">
2400+ <font>
2401+ <weight>75</weight>
2402+ <bold>true</bold>
2403+ </font>
2404+ </property>
2405+ <property name="text">
2406+ <string>password_label</string>
2407+ </property>
2408+ </widget>
2409+ </item>
2410+ <item>
2411+ <widget class="QLineEdit" name="password_edit">
2412+ <property name="sizePolicy">
2413+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
2414+ <horstretch>0</horstretch>
2415+ <verstretch>0</verstretch>
2416+ </sizepolicy>
2417+ </property>
2418+ <property name="minimumSize">
2419+ <size>
2420+ <width>300</width>
2421+ <height>0</height>
2422+ </size>
2423+ </property>
2424+ <property name="maximumSize">
2425+ <size>
2426+ <width>300</width>
2427+ <height>16777215</height>
2428+ </size>
2429+ </property>
2430+ <property name="font">
2431+ <font>
2432+ <pointsize>11</pointsize>
2433+ </font>
2434+ </property>
2435+ <property name="toolTip">
2436+ <string>Your password must be at least 8 characters long and at least contain one number and one upper later.</string>
2437+ </property>
2438+ <property name="statusTip">
2439+ <string/>
2440+ </property>
2441+ <property name="echoMode">
2442+ <enum>QLineEdit::Password</enum>
2443+ </property>
2444+ <property name="placeholderText">
2445+ <string/>
2446+ </property>
2447+ <property name="formError" stdset="0">
2448+ <bool>false</bool>
2449+ </property>
2450+ </widget>
2451+ </item>
2452+ </layout>
2453+ </item>
2454+ <item row="7" column="0">
2455+ <layout class="QVBoxLayout" name="verticalLayout">
2456+ <property name="spacing">
2457+ <number>3</number>
2458+ </property>
2459+ <item>
2460+ <widget class="QLabel" name="confirm_password_label">
2461+ <property name="font">
2462+ <font>
2463+ <weight>75</weight>
2464+ <bold>true</bold>
2465+ </font>
2466+ </property>
2467+ <property name="text">
2468+ <string>confirm_password_label</string>
2469+ </property>
2470+ </widget>
2471+ </item>
2472+ <item>
2473+ <widget class="QLineEdit" name="confirm_password_edit">
2474+ <property name="sizePolicy">
2475+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
2476+ <horstretch>0</horstretch>
2477+ <verstretch>0</verstretch>
2478+ </sizepolicy>
2479+ </property>
2480+ <property name="minimumSize">
2481+ <size>
2482+ <width>300</width>
2483+ <height>0</height>
2484+ </size>
2485+ </property>
2486+ <property name="maximumSize">
2487+ <size>
2488+ <width>300</width>
2489+ <height>16777215</height>
2490+ </size>
2491+ </property>
2492+ <property name="font">
2493+ <font>
2494+ <pointsize>11</pointsize>
2495+ </font>
2496+ </property>
2497+ <property name="echoMode">
2498+ <enum>QLineEdit::Password</enum>
2499+ </property>
2500+ <property name="placeholderText">
2501+ <string/>
2502+ </property>
2503+ <property name="formError" stdset="0">
2504+ <bool>false</bool>
2505+ </property>
2506+ </widget>
2507+ </item>
2508+ </layout>
2509+ </item>
2510+ <item row="9" column="0">
2511+ <layout class="QVBoxLayout" name="verticalLayout">
2512+ <property name="spacing">
2513+ <number>3</number>
2514+ </property>
2515+ <item>
2516+ <widget class="QLabel" name="captcha_view">
2517+ <property name="sizePolicy">
2518+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
2519+ <horstretch>0</horstretch>
2520+ <verstretch>0</verstretch>
2521+ </sizepolicy>
2522+ </property>
2523+ <property name="minimumSize">
2524+ <size>
2525+ <width>300</width>
2526+ <height>57</height>
2527+ </size>
2528+ </property>
2529+ <property name="maximumSize">
2530+ <size>
2531+ <width>300</width>
2532+ <height>16777215</height>
2533+ </size>
2534+ </property>
2535+ <property name="styleSheet">
2536+ <string notr="true">background-color: white</string>
2537+ </property>
2538+ <property name="frameShape">
2539+ <enum>QFrame::Box</enum>
2540+ </property>
2541+ <property name="text">
2542+ <string>If you can't read this then &lt;a href=&quot;example.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#dd4814;&quot;&gt;refresh&lt;/span&gt;&lt;/a&gt; this page&lt;/span&gt;</string>
2543+ </property>
2544+ </widget>
2545+ </item>
2546+ <item>
2547+ <widget class="QLineEdit" name="captcha_solution_edit">
2548+ <property name="sizePolicy">
2549+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
2550+ <horstretch>0</horstretch>
2551+ <verstretch>0</verstretch>
2552+ </sizepolicy>
2553+ </property>
2554+ <property name="minimumSize">
2555+ <size>
2556+ <width>300</width>
2557+ <height>0</height>
2558+ </size>
2559+ </property>
2560+ <property name="maximumSize">
2561+ <size>
2562+ <width>300</width>
2563+ <height>16777215</height>
2564+ </size>
2565+ </property>
2566+ <property name="font">
2567+ <font>
2568+ <pointsize>11</pointsize>
2569+ </font>
2570+ </property>
2571+ <property name="locale">
2572+ <locale language="English" country="UnitedStates"/>
2573+ </property>
2574+ <property name="inputMask">
2575+ <string/>
2576+ </property>
2577+ <property name="text">
2578+ <string/>
2579+ </property>
2580+ <property name="placeholderText">
2581+ <string/>
2582+ </property>
2583+ <property name="formError" stdset="0">
2584+ <bool>false</bool>
2585+ </property>
2586+ </widget>
2587+ </item>
2588+ </layout>
2589+ </item>
2590+ <item row="9" column="1">
2591+ <widget class="QLabel" name="refresh_label">
2592+ <property name="sizePolicy">
2593+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
2594+ <horstretch>0</horstretch>
2595+ <verstretch>0</verstretch>
2596+ </sizepolicy>
2597+ </property>
2598+ <property name="minimumSize">
2599+ <size>
2600+ <width>220</width>
2601+ <height>0</height>
2602+ </size>
2603+ </property>
2604+ <property name="maximumSize">
2605+ <size>
2606+ <width>220</width>
2607+ <height>16777215</height>
2608+ </size>
2609+ </property>
2610+ <property name="locale">
2611+ <locale language="English" country="UnitedStates"/>
2612+ </property>
2613+ <property name="text">
2614+ <string>If you can't read this then &lt;a href=&quot;example.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#dd4814;&quot;&gt;refresh&lt;/span&gt;&lt;/a&gt; this page&lt;/span&gt;</string>
2615+ </property>
2616+ <property name="wordWrap">
2617+ <bool>true</bool>
2618+ </property>
2619+ <property name="indent">
2620+ <number>0</number>
2621+ </property>
2622+ </widget>
2623+ </item>
2624+ <item row="1" column="1">
2625+ <layout class="QVBoxLayout" name="verticalLayout_7">
2626+ <property name="spacing">
2627+ <number>0</number>
2628+ </property>
2629+ <property name="leftMargin">
2630+ <number>0</number>
2631+ </property>
2632+ <item>
2633+ <widget class="QLabel" name="name_assistance">
2634+ <property name="sizePolicy">
2635+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
2636+ <horstretch>0</horstretch>
2637+ <verstretch>0</verstretch>
2638+ </sizepolicy>
2639+ </property>
2640+ <property name="minimumSize">
2641+ <size>
2642+ <width>220</width>
2643+ <height>0</height>
2644+ </size>
2645+ </property>
2646+ <property name="maximumSize">
2647+ <size>
2648+ <width>220</width>
2649+ <height>16777215</height>
2650+ </size>
2651+ </property>
2652+ <property name="text">
2653+ <string>name_assistance</string>
2654+ </property>
2655+ <property name="alignment">
2656+ <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
2657+ </property>
2658+ <property name="wordWrap">
2659+ <bool>true</bool>
2660+ </property>
2661+ </widget>
2662+ </item>
2663+ </layout>
2664+ </item>
2665+ <item row="3" column="1">
2666+ <layout class="QVBoxLayout" name="verticalLayout_8">
2667+ <property name="spacing">
2668+ <number>0</number>
2669+ </property>
2670+ <property name="leftMargin">
2671+ <number>0</number>
2672+ </property>
2673+ <item>
2674+ <widget class="QLabel" name="email_assistance">
2675+ <property name="sizePolicy">
2676+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
2677+ <horstretch>0</horstretch>
2678+ <verstretch>0</verstretch>
2679+ </sizepolicy>
2680+ </property>
2681+ <property name="minimumSize">
2682+ <size>
2683+ <width>220</width>
2684+ <height>0</height>
2685+ </size>
2686+ </property>
2687+ <property name="maximumSize">
2688+ <size>
2689+ <width>220</width>
2690+ <height>16777215</height>
2691+ </size>
2692+ </property>
2693+ <property name="text">
2694+ <string>email_assistance</string>
2695+ </property>
2696+ <property name="alignment">
2697+ <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
2698+ </property>
2699+ <property name="wordWrap">
2700+ <bool>true</bool>
2701+ </property>
2702+ </widget>
2703+ </item>
2704+ </layout>
2705+ </item>
2706+ <item row="4" column="1">
2707+ <layout class="QVBoxLayout" name="verticalLayout_9">
2708+ <property name="spacing">
2709+ <number>0</number>
2710+ </property>
2711+ <property name="leftMargin">
2712+ <number>0</number>
2713+ </property>
2714+ <item>
2715+ <widget class="QLabel" name="confirm_email_assistance">
2716+ <property name="sizePolicy">
2717+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
2718+ <horstretch>0</horstretch>
2719+ <verstretch>0</verstretch>
2720+ </sizepolicy>
2721+ </property>
2722+ <property name="minimumSize">
2723+ <size>
2724+ <width>220</width>
2725+ <height>0</height>
2726+ </size>
2727+ </property>
2728+ <property name="maximumSize">
2729+ <size>
2730+ <width>220</width>
2731+ <height>16777215</height>
2732+ </size>
2733+ </property>
2734+ <property name="text">
2735+ <string>confirm_email_assistance</string>
2736+ </property>
2737+ <property name="alignment">
2738+ <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
2739+ </property>
2740+ <property name="wordWrap">
2741+ <bool>true</bool>
2742+ </property>
2743+ <property name="indent">
2744+ <number>0</number>
2745+ </property>
2746+ </widget>
2747+ </item>
2748+ </layout>
2749+ </item>
2750+ <item row="6" column="1" rowspan="2">
2751+ <widget class="QLabel" name="password_assistance">
2752+ <property name="sizePolicy">
2753+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
2754+ <horstretch>0</horstretch>
2755+ <verstretch>0</verstretch>
2756+ </sizepolicy>
2757+ </property>
2758+ <property name="minimumSize">
2759+ <size>
2760+ <width>220</width>
2761+ <height>0</height>
2762+ </size>
2763+ </property>
2764+ <property name="maximumSize">
2765+ <size>
2766+ <width>220</width>
2767+ <height>16777215</height>
2768+ </size>
2769+ </property>
2770+ <property name="text">
2771+ <string>password_assistance</string>
2772+ </property>
2773+ <property name="wordWrap">
2774+ <bool>true</bool>
2775+ </property>
2776+ <property name="indent">
2777+ <number>17</number>
2778+ </property>
2779+ </widget>
2780+ </item>
2781+ <item row="2" column="1">
2782+ <spacer name="verticalSpacer">
2783+ <property name="orientation">
2784+ <enum>Qt::Vertical</enum>
2785+ </property>
2786+ <property name="sizeType">
2787+ <enum>QSizePolicy::Fixed</enum>
2788+ </property>
2789+ <property name="sizeHint" stdset="0">
2790+ <size>
2791+ <width>20</width>
2792+ <height>15</height>
2793+ </size>
2794+ </property>
2795+ </spacer>
2796+ </item>
2797+ <item row="5" column="1">
2798 <spacer name="verticalSpacer_2">
2799 <property name="orientation">
2800 <enum>Qt::Vertical</enum>
2801 </property>
2802- <property name="sizeHint" stdset="0">
2803- <size>
2804- <width>20</width>
2805- <height>40</height>
2806- </size>
2807- </property>
2808- </spacer>
2809- </item>
2810+ <property name="sizeType">
2811+ <enum>QSizePolicy::Fixed</enum>
2812+ </property>
2813+ <property name="sizeHint" stdset="0">
2814+ <size>
2815+ <width>20</width>
2816+ <height>15</height>
2817+ </size>
2818+ </property>
2819+ </spacer>
2820+ </item>
2821+ <item row="8" column="1">
2822+ <spacer name="verticalSpacer_3">
2823+ <property name="orientation">
2824+ <enum>Qt::Vertical</enum>
2825+ </property>
2826+ <property name="sizeType">
2827+ <enum>QSizePolicy::Fixed</enum>
2828+ </property>
2829+ <property name="sizeHint" stdset="0">
2830+ <size>
2831+ <width>20</width>
2832+ <height>15</height>
2833+ </size>
2834+ </property>
2835+ </spacer>
2836+ </item>
2837+ </layout>
2838+ </item>
2839+ <item>
2840+ <layout class="QHBoxLayout" name="hlayout_check">
2841+ <property name="spacing">
2842+ <number>0</number>
2843+ </property>
2844 </layout>
2845 </item>
2846 </layout>
2847 </widget>
2848- <resources/>
2849 <connections/>
2850 </ui>
2851
2852=== modified file 'run-tests'
2853--- run-tests 2011-12-09 14:07:38 +0000
2854+++ run-tests 2012-02-14 22:04:20 +0000
2855@@ -18,16 +18,10 @@
2856
2857 QT_TESTS_PATH=ubuntu_sso/qt/tests
2858 GTK_TESTS_PATH=ubuntu_sso/gtk/tests
2859+WINDOWS_TESTS=test_windows.py
2860
2861 set -e
2862
2863-if [ "$1" == "-qt" ]; then
2864- USE_QT=1
2865- shift
2866-else
2867- USE_QT=0
2868-fi
2869-
2870 if [ $# -ne 0 ]; then
2871 # run specific module given by the caller
2872 MODULE="$@"
2873@@ -37,24 +31,34 @@
2874 fi
2875
2876 style_check() {
2877- ./setup.py clean
2878- u1lint
2879+ u1lint --ignore ubuntu_sso/qt/ui
2880 if [ -x `which pep8` ]; then
2881- pep8 --repeat .
2882+ pep8 --exclude '.svn,CVS,.bzr,.hg,.git,*_ui.py,*_rc.py' --repeat . bin/*
2883 else
2884 echo "Please install the 'pep8' package."
2885 fi
2886 }
2887-
2888 unset GTK_MODULES
2889
2890-echo "Running test suite for ""$MODULE"
2891-if [ "$USE_QT" -eq 0 ]; then
2892- `which xvfb-run` u1trial -p "$QT_TESTS_PATH" -i "test_windows.py" "$MODULE"
2893-else
2894- ./setup.py build
2895- `which xvfb-run` u1trial -p "$GTK_TESTS_PATH" -i "test_windows.py" --reactor=qt4 --gui "$MODULE"
2896+XVFB_CMDLINE=""
2897+XVFB=$(which xvfb-run)
2898+if [ $XVFB ]; then
2899+ XVFB_CMDLINE="$XVFB -a"
2900 fi
2901+
2902+echo "*** Running GTK test suite for ""$MODULE"" ***"
2903+$XVFB_CMDLINE u1trial --reactor=gi --gui -p "$QT_TESTS_PATH" -i "test_windows.py" "$MODULE"
2904+rm -rf _trial_temp
2905+
2906+# hack to avoid:
2907+# g_dbus_connection_real_closed: Remote peer vanished with error: Underlying
2908+# GIOStream returned 0 bytes on an async read (g-io-error-quark, 0). Exiting.
2909+sleep 3
2910+
2911+echo "*** Running QT test suite for ""$MODULE"" ***"
2912+./setup.py build
2913+USE_QT_MAINLOOP=True $XVFB_CMDLINE u1trial --reactor=qt4 --gui -p "$GTK_TESTS_PATH" -i "test_windows.py" "$MODULE"
2914+rm -rf _trial_temp
2915+rm -rf build
2916+
2917 style_check
2918-rm -rf _trial_temp
2919-rm -rf build
2920
2921=== modified file 'setup.py'
2922--- setup.py 2012-02-02 13:37:55 +0000
2923+++ setup.py 2012-02-14 22:04:20 +0000
2924@@ -1,11 +1,7 @@
2925 #!/usr/bin/env python
2926 # setup.py - Build system for Ubuntu SSO Client package
2927 #
2928-# Authors: Natalia B. Bidart <natalia.bidart@canonical.com>
2929-# Manuel de la Pena <manuel@canonical.com>
2930-# Alejandro J. Cura <alecu@canonical.com>
2931-#
2932-# Copyright 2010-2011 Canonical Ltd.
2933+# Copyright 2010-2012 Canonical Ltd.
2934 #
2935 # This program is free software: you can redistribute it and/or modify it
2936 # under the terms of the GNU General Public License version 3, as published
2937@@ -40,15 +36,16 @@
2938
2939 POT_FILE = 'po/ubuntu-sso-client.pot'
2940 SERVICE_FILE = 'data/com.ubuntu.sso.service'
2941+CONSTANTS = 'ubuntu_sso/constants.py'
2942
2943-CLEANFILES = [SERVICE_FILE, POT_FILE, 'MANIFEST']
2944-QT_UI_DIR = os.path.join('ubuntu_sso', 'qt')
2945+CLEANFILES = [SERVICE_FILE, POT_FILE, CONSTANTS, 'MANIFEST']
2946+QT_UI_DIR = os.path.join('ubuntu_sso', 'qt', 'ui')
2947
2948
2949 def replace_prefix(prefix):
2950 """Replace every '@prefix@' with prefix within 'filename' content."""
2951- # replace .service file
2952- for filename in (SERVICE_FILE,):
2953+ # replace .service file, DATA_DIR constant
2954+ for filename in (SERVICE_FILE, CONSTANTS):
2955 with open(filename + '.in') as in_file:
2956 content = in_file.read()
2957 with open(filename, 'w') as out_file:
2958@@ -112,7 +109,8 @@
2959 path = os.getenv('PATH')
2960 os.putenv('PATH', path + os.path.pathsep + os.path.join(
2961 os.path.dirname(PyQt4.__file__), 'bin'))
2962- if os.system('pyrcc4 "%s" -o "%s"' % (qrc_file, py_file)) > 0:
2963+ if os.system('pyrcc4 -no-compress "%s" -o "%s"' %
2964+ (qrc_file, py_file)) > 0:
2965 self.warn('Unable to generate python module {py_file}'
2966 ' for resource file {qrc_file}'.format(
2967 py_file=py_file, qrc_file=qrc_file))
2968@@ -313,6 +311,14 @@
2969 }
2970
2971
2972+sso_executables = [
2973+ 'bin/ubuntu-sso-login',
2974+ 'bin/ubuntu-sso-login-gtk',
2975+ 'bin/ubuntu-sso-login-qt',
2976+ 'bin/ubuntu-sso-proxy-creds-qt',
2977+]
2978+
2979+
2980 class dummy_build_i18n(distutils.cmd.Command):
2981
2982 """Dummy for windows."""
2983@@ -326,6 +332,7 @@
2984 def run(self, *args):
2985 """Dummy."""
2986
2987+
2988 if sys.platform == 'win32':
2989 cmdclass['build_i18n'] = dummy_build_i18n
2990
2991@@ -349,7 +356,7 @@
2992 },
2993 },
2994 # add the console script so that py2exe compiles it
2995- 'console': ['bin/ubuntu-sso-login'],
2996+ 'console': sso_executables,
2997 'zipfile': None,
2998 }
2999 return _data_files, _extra
3000@@ -358,10 +365,8 @@
3001 data_files, extra = setup_windows()
3002 else:
3003 data_files = [
3004- ('lib/ubuntu-sso-client', ['bin/ubuntu-sso-login']),
3005- ('lib/ubuntu-sso-client', ['bin/ubuntu-sso-login-gtk']),
3006+ ('lib/ubuntu-sso-client', sso_executables),
3007 ('share/dbus-1/services', ['data/com.ubuntu.sso.service']),
3008- ('share/ubuntu-sso-client/data/gtk', ['data/gtk/ui.glade']),
3009 ]
3010 extra = {}
3011
3012@@ -379,14 +384,24 @@
3013 data_files=data_files,
3014 packages=[
3015 'ubuntu_sso',
3016+ 'ubuntu_sso.tests',
3017 'ubuntu_sso.gtk',
3018 'ubuntu_sso.keyring',
3019+ 'ubuntu_sso.keyring.tests',
3020 'ubuntu_sso.main',
3021+ 'ubuntu_sso.main.tests',
3022 'ubuntu_sso.networkstate',
3023+ 'ubuntu_sso.networkstate.tests',
3024 'ubuntu_sso.qt',
3025+ 'ubuntu_sso.qt.ui',
3026 'ubuntu_sso.utils',
3027+ 'ubuntu_sso.utils.tests',
3028+ 'ubuntu_sso.utils.runner',
3029+ 'ubuntu_sso.utils.runner.tests',
3030 'ubuntu_sso.utils.webclient',
3031+ 'ubuntu_sso.utils.webclient.tests',
3032 'ubuntu_sso.xdg_base_directory',
3033+ 'ubuntu_sso.xdg_base_directory.tests',
3034 ],
3035 cmdclass=cmdclass,
3036 **extra)
3037
3038=== modified file 'ubuntu_sso/__init__.py'
3039--- ubuntu_sso/__init__.py 2010-10-07 21:09:01 +0000
3040+++ ubuntu_sso/__init__.py 2012-02-14 22:04:20 +0000
3041@@ -15,17 +15,21 @@
3042 # with this program. If not, see <http://www.gnu.org/licenses/>.
3043 """Ubuntu Single Sign On client code."""
3044
3045-# constants
3046+# DBus constants
3047 DBUS_BUS_NAME = "com.ubuntu.sso"
3048-DBUS_PATH = "/sso" # deprecated!
3049-DBUS_CRED_PATH = "/credentials" # deprecated!
3050+
3051 DBUS_ACCOUNT_PATH = "/com/ubuntu/sso/accounts"
3052-
3053-DBUS_IFACE_AUTH_NAME = "com.ubuntu.sso"
3054 DBUS_IFACE_USER_NAME = "com.ubuntu.sso.UserManagement"
3055-DBUS_IFACE_CRED_NAME = "com.ubuntu.sso.ApplicationCredentials"
3056
3057 DBUS_CREDENTIALS_PATH = "/com/ubuntu/sso/credentials"
3058 DBUS_CREDENTIALS_IFACE = "com.ubuntu.sso.CredentialsManagement"
3059
3060 NO_OP = lambda *args, **kwargs: None
3061+
3062+# return codes for UIs
3063+USER_SUCCESS = 0
3064+USER_CANCELLATION = 10
3065+
3066+# available UIs
3067+UI_EXECUTABLE_GTK = 'ubuntu-sso-login-gtk'
3068+UI_EXECUTABLE_QT = 'ubuntu-sso-login-qt'
3069
3070=== modified file 'ubuntu_sso/account.py'
3071--- ubuntu_sso/account.py 2011-12-15 20:52:32 +0000
3072+++ ubuntu_sso/account.py 2012-02-14 22:04:20 +0000
3073@@ -16,27 +16,27 @@
3074 #
3075 # You should have received a copy of the GNU General Public License along
3076 # with this program. If not, see <http://www.gnu.org/licenses/>.
3077-"""Single Sign On account management."""
3078+"""Single Sign On account management.
3079+
3080+All the methods in Account expect unicode as parameters.
3081+
3082+"""
3083
3084 import os
3085 import re
3086-import urllib2
3087
3088-# Unable to import 'lazr.restfulclient.*'
3089-# pylint: disable=F0401
3090-from lazr.restfulclient.authorize import BasicHttpAuthorizer
3091 from lazr.restfulclient.authorize.oauth import OAuthAuthorizer
3092-from lazr.restfulclient.errors import HTTPError
3093-from lazr.restfulclient.resource import ServiceRoot
3094-# pylint: enable=F0401
3095 from oauth import oauth
3096+from twisted.internet import defer
3097
3098 from ubuntu_sso.logger import setup_logging
3099-from ubuntu_sso.utils import timestamp_checker
3100+from ubuntu_sso.utils import webclient
3101+from ubuntu_sso.utils.webclient import restful
3102+from ubuntu_sso.utils.webclient.common import WebClientError
3103
3104
3105 logger = setup_logging("ubuntu_sso.account")
3106-SERVICE_URL = "https://login.ubuntu.com/api/1.0"
3107+SERVICE_URL = u"https://login.ubuntu.com/api/1.0/"
3108 SSO_STATUS_OK = 'ok'
3109 SSO_STATUS_ERROR = 'error'
3110
3111@@ -102,8 +102,9 @@
3112 self.service_url = service_url
3113 else:
3114 self.service_url = os.environ.get('USSOC_SERVICE_URL', SERVICE_URL)
3115- logger.info('Created a new SSO access layer for service url %r',
3116+ logger.info('Creating a new SSO access layer for service url %r',
3117 self.service_url)
3118+ assert self.service_url.endswith("/")
3119
3120 def _valid_email(self, email):
3121 """Validate the given email."""
3122@@ -127,46 +128,57 @@
3123 result[key] = "\n".join(val)
3124 return result
3125
3126+ @defer.inlineCallbacks
3127 def generate_captcha(self, filename):
3128 """Generate a captcha using the SSO service."""
3129 logger.debug('generate_captcha: requesting captcha, filename: %r',
3130 filename)
3131- sso_service = ServiceRoot(None, self.service_url)
3132- captcha = sso_service.captchas.new()
3133+ restful_client = restful.RestfulClient(self.service_url)
3134+ try:
3135+ captcha = yield restful_client.restcall(u"captchas.new")
3136+ finally:
3137+ restful_client.shutdown()
3138
3139 # download captcha and save to 'filename'
3140 logger.debug('generate_captcha: server answered: %r', captcha)
3141+ wc = webclient.webclient_factory()
3142 try:
3143- res = urllib2.urlopen(captcha['image_url'])
3144+ response = yield wc.request(captcha['image_url'])
3145 with open(filename, 'wb') as f:
3146- f.write(res.read())
3147+ f.write(response.content)
3148 except:
3149 msg = 'generate_captcha crashed while downloading the image.'
3150 logger.exception(msg)
3151 raise
3152-
3153- return captcha['captcha_id']
3154-
3155+ finally:
3156+ wc.shutdown()
3157+
3158+ defer.returnValue(captcha['captcha_id'])
3159+
3160+ @defer.inlineCallbacks
3161 def register_user(self, email, password, displayname,
3162 captcha_id, captcha_solution):
3163 """Register a new user with 'email' and 'password'."""
3164 logger.debug('register_user: email: %r password: <hidden>, '
3165 'displayname: %r, captcha_id: %r, captcha_solution: %r',
3166 email, displayname, captcha_id, captcha_solution)
3167- sso_service = ServiceRoot(None, self.service_url)
3168- if not self._valid_email(email):
3169- logger.error('register_user: InvalidEmailError for email: %r',
3170- email)
3171- raise InvalidEmailError()
3172- if not self._valid_password(password):
3173- logger.error('register_user: InvalidPasswordError')
3174- raise InvalidPasswordError()
3175+ restful_client = restful.RestfulClient(self.service_url)
3176+ try:
3177+ if not self._valid_email(email):
3178+ logger.error('register_user: InvalidEmailError for email: %r',
3179+ email)
3180+ raise InvalidEmailError()
3181+ if not self._valid_password(password):
3182+ logger.error('register_user: InvalidPasswordError')
3183+ raise InvalidPasswordError()
3184
3185- result = sso_service.registrations.register(
3186- email=email, password=password,
3187- displayname=displayname,
3188- captcha_id=captcha_id,
3189- captcha_solution=captcha_solution)
3190+ result = yield restful_client.restcall(u"registration.register",
3191+ email=email, password=password,
3192+ displayname=displayname,
3193+ captcha_id=captcha_id,
3194+ captcha_solution=captcha_solution)
3195+ finally:
3196+ restful_client.shutdown()
3197 logger.info('register_user: email: %r result: %r', email, result)
3198
3199 if result['status'].lower() == SSO_STATUS_ERROR:
3200@@ -175,87 +187,91 @@
3201 elif result['status'].lower() != SSO_STATUS_OK:
3202 raise RegistrationError('Received unknown status: %s' % result)
3203 else:
3204- return email
3205+ defer.returnValue(email)
3206
3207+ @defer.inlineCallbacks
3208 def login(self, email, password, token_name):
3209 """Login a user with 'email' and 'password'."""
3210 logger.debug('login: email: %r password: <hidden>, token_name: %r',
3211 email, token_name)
3212- basic = BasicHttpAuthorizer(email, password)
3213- sso_service = ServiceRoot(basic, self.service_url)
3214- service = sso_service.authentications.authenticate
3215-
3216+ restful_client = restful.RestfulClient(self.service_url,
3217+ username=email,
3218+ password=password)
3219 try:
3220- credentials = service(token_name=token_name)
3221- except HTTPError:
3222+ credentials = yield restful_client.restcall(
3223+ u"authentications.authenticate",
3224+ token_name=token_name)
3225+ except WebClientError:
3226 logger.exception('login failed with:')
3227 raise AuthenticationError()
3228+ finally:
3229+ restful_client.shutdown()
3230
3231 logger.debug('login: authentication successful! consumer_key: %r, ' \
3232 'token_name: %r', credentials['consumer_key'], token_name)
3233- return credentials
3234+ defer.returnValue(credentials)
3235
3236- def is_validated(self, token, sso_service=None):
3237+ @defer.inlineCallbacks
3238+ def is_validated(self, token):
3239 """Return if user with 'email' and 'password' is validated."""
3240 logger.debug('is_validated: requesting accounts.me() info.')
3241- if sso_service is None:
3242- oauth_token = oauth.OAuthToken(token['token'],
3243- token['token_secret'])
3244- authorizer = TimestampedAuthorizer(
3245- timestamp_checker.get_faithful_time,
3246- token['consumer_key'],
3247- token['consumer_secret'],
3248- oauth_token)
3249- sso_service = ServiceRoot(authorizer, self.service_url)
3250-
3251- me_info = sso_service.accounts.me()
3252+ restful_client = restful.RestfulClient(self.service_url,
3253+ oauth_credentials=token)
3254+ try:
3255+ me_info = yield restful_client.restcall(u"accounts.me")
3256+ finally:
3257+ restful_client.shutdown()
3258 key = 'preferred_email'
3259 result = key in me_info and me_info[key] != None
3260
3261 logger.info('is_validated: consumer_key: %r, result: %r.',
3262 token['consumer_key'], result)
3263- return result
3264+ defer.returnValue(result)
3265
3266+ @defer.inlineCallbacks
3267 def validate_email(self, email, password, email_token, token_name):
3268 """Validate an email token for user with 'email' and 'password'."""
3269 logger.debug('validate_email: email: %r password: <hidden>, '
3270 'email_token: %r, token_name: %r.',
3271 email, email_token, token_name)
3272- token = self.login(email=email, password=password,
3273- token_name=token_name)
3274-
3275- oauth_token = oauth.OAuthToken(token['token'], token['token_secret'])
3276- authorizer = TimestampedAuthorizer(timestamp_checker.get_faithful_time,
3277- token['consumer_key'],
3278- token['consumer_secret'],
3279- oauth_token)
3280- sso_service = ServiceRoot(authorizer, self.service_url)
3281- result = sso_service.accounts.validate_email(email_token=email_token)
3282+ credentials = yield self.login(email=email, password=password,
3283+ token_name=token_name)
3284+ restful_client = restful.RestfulClient(self.service_url,
3285+ oauth_credentials=credentials)
3286+ try:
3287+ result = yield restful_client.restcall(u"accounts.validate_email",
3288+ email_token=email_token)
3289+ finally:
3290+ restful_client.shutdown()
3291 logger.info('validate_email: email: %r result: %r', email, result)
3292 if 'errors' in result:
3293 errorsdict = self._format_webservice_errors(result['errors'])
3294 raise EmailTokenError(errorsdict)
3295 elif 'email' in result:
3296- return token
3297+ defer.returnValue(credentials)
3298 else:
3299 raise EmailTokenError('Received invalid reply: %s' % result)
3300
3301+ @defer.inlineCallbacks
3302 def request_password_reset_token(self, email):
3303 """Request a token to reset the password for the account 'email'."""
3304- sso_service = ServiceRoot(None, self.service_url)
3305- service = sso_service.registrations.request_password_reset_token
3306+ restful_client = restful.RestfulClient(self.service_url)
3307 try:
3308- result = service(email=email)
3309- except HTTPError, e:
3310+ operation = u"registration.request_password_reset_token"
3311+ result = yield restful_client.restcall(operation, email=email)
3312+ except WebClientError, e:
3313 logger.exception('request_password_reset_token failed with:')
3314- raise ResetPasswordTokenError(e.content.split('\n')[0])
3315+ raise ResetPasswordTokenError(e[1].split('\n')[0])
3316+ finally:
3317+ restful_client.shutdown()
3318
3319 if result['status'].lower() == SSO_STATUS_OK:
3320- return email
3321+ defer.returnValue(email)
3322 else:
3323 raise ResetPasswordTokenError('Received invalid reply: %s' %
3324 result)
3325
3326+ @defer.inlineCallbacks
3327 def set_new_password(self, email, token, new_password):
3328 """Set a new password for the account 'email' to be 'new_password'.
3329
3330@@ -263,16 +279,19 @@
3331 'request_password_reset_token'.
3332
3333 """
3334- sso_service = ServiceRoot(None, self.service_url)
3335- service = sso_service.registrations.set_new_password
3336+ restful_client = restful.RestfulClient(self.service_url)
3337 try:
3338- result = service(email=email, token=token,
3339- new_password=new_password)
3340- except HTTPError, e:
3341+ result = yield restful_client.restcall(
3342+ u"registration.set_new_password",
3343+ email=email, token=token,
3344+ new_password=new_password)
3345+ except WebClientError, e:
3346 logger.exception('set_new_password failed with:')
3347- raise NewPasswordError(e.content.split('\n')[0])
3348+ raise NewPasswordError(e[1].split('\n')[0])
3349+ finally:
3350+ restful_client.shutdown()
3351
3352 if result['status'].lower() == SSO_STATUS_OK:
3353- return email
3354+ defer.returnValue(email)
3355 else:
3356 raise NewPasswordError('Received invalid reply: %s' % result)
3357
3358=== added file 'ubuntu_sso/constants.py.in'
3359--- ubuntu_sso/constants.py.in 1970-01-01 00:00:00 +0000
3360+++ ubuntu_sso/constants.py.in 2012-02-14 22:04:20 +0000
3361@@ -0,0 +1,28 @@
3362+# -*- coding: utf-8 -*-
3363+#
3364+# Copyright 2012 Canonical Ltd.
3365+#
3366+# This program is free software: you can redistribute it and/or modify it
3367+# under the terms of the GNU General Public License version 3, as published
3368+# by the Free Software Foundation.
3369+#
3370+# This program is distributed in the hope that it will be useful, but
3371+# WITHOUT ANY WARRANTY; without even the implied warranties of
3372+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3373+# PURPOSE. See the GNU General Public License for more details.
3374+#
3375+# You should have received a copy of the GNU General Public License along
3376+# with this program. If not, see <http://www.gnu.org/licenses/>.
3377+
3378+"""Some generated constants.
3379+
3380+DO NO EDIT! This is a generated file. It will be built at installation time.
3381+
3382+"""
3383+
3384+import os
3385+
3386+
3387+PROJECT_NAME = 'ubuntu-sso-client'
3388+PROJECT_DIR = os.path.join('@prefix@', 'share', PROJECT_NAME)
3389+BIN_DIR = os.path.join('@prefix@', 'lib', PROJECT_NAME)
3390
3391=== modified file 'ubuntu_sso/credentials.py'
3392--- ubuntu_sso/credentials.py 2012-01-17 15:09:12 +0000
3393+++ ubuntu_sso/credentials.py 2012-02-14 22:04:20 +0000
3394@@ -1,9 +1,6 @@
3395 # -*- coding: utf-8 -*-
3396-
3397-# Author: Natalia Bidart <natalia.bidart@canonical.com>
3398-# Author: Alejandro J. Cura <alecu@canonical.com>
3399 #
3400-# Copyright 2010 Canonical Ltd.
3401+# Copyright 2010-2012 Canonical Ltd.
3402 #
3403 # This program is free software: you can redistribute it and/or modify it
3404 # under the terms of the GNU General Public License version 3, as published
3405@@ -26,28 +23,24 @@
3406 * register
3407 * login
3408
3409-The first three return a Deferred that will be fired when the operation was
3410+All the methods return a Deferred that will be fired when the operation was
3411 completed.
3412
3413-The second two use the 'success_cb', 'error_cb' and 'denial_cb' to signal the
3414-caller when the credentials were retrieved successfully, when there was an
3415-error or when the user denied the access to the application, respectively.
3416-
3417 For details, please read the Credentials class documentation.
3418
3419 """
3420
3421-import sys
3422-import traceback
3423-import urllib2
3424+import os
3425
3426 from functools import wraps
3427
3428 from twisted.internet import defer
3429
3430-from ubuntu_sso import NO_OP, utils
3431+from ubuntu_sso import UI_EXECUTABLE_GTK, USER_CANCELLATION, USER_SUCCESS
3432 from ubuntu_sso.keyring import Keyring
3433 from ubuntu_sso.logger import setup_logging
3434+from ubuntu_sso.utils import get_bin_dir, runner
3435+
3436
3437 logger = setup_logging('ubuntu_sso.credentials')
3438
3439@@ -57,44 +50,20 @@
3440 HELP_TEXT_KEY = 'help_text'
3441 WINDOW_ID_KEY = 'window_id'
3442 PING_URL_KEY = 'ping_url'
3443-UI_MODULE_KEY = 'ui_module'
3444-UI_CLASS_KEY = 'ui_class'
3445-SUCCESS_CB_KEY = 'success_cb'
3446-ERROR_CB_KEY = 'error_cb'
3447-DENIAL_CB_KEY = 'denial_cb'
3448-ERROR_KEY = 'error_message'
3449-ERROR_DETAIL_KEY = 'detailed_error'
3450-
3451-
3452-def handle_exceptions(msg):
3453- """Handle exceptions using 'msg' as error message."""
3454-
3455- def middle(f):
3456- """Decorate 'f' to catch all errors."""
3457-
3458- @wraps(f)
3459- def inner(self, *a, **kw):
3460- """Call 'f' within a try-except block.
3461-
3462- If any exception occurs, self.error_cb is called and the exception
3463- is logged.
3464- """
3465- result = None
3466- try:
3467- result = f(self, *a, **kw)
3468- except: # pylint: disable=W0702
3469- logger.exception('%s (app_name: %s): %s.',
3470- f.__name__, self.app_name, msg)
3471- logger.error('%s (app_name: %s): Calling error_cb at %r.',
3472- f.__name__, self.app_name, self.error_cb)
3473- error_dict = {ERROR_KEY: msg,
3474- ERROR_DETAIL_KEY: traceback.format_exc()}
3475- self.error_cb(error_dict)
3476- return result
3477-
3478- return inner
3479-
3480- return middle
3481+POLICY_URL_KEY = 'policy_url'
3482+UI_EXECUTABLE_KEY = 'ui_executable'
3483+
3484+
3485+class CredentialsError(Exception):
3486+ """Generic credentials error."""
3487+
3488+
3489+class UserCancellationError(CredentialsError):
3490+ """The user cancelled the process of authentication."""
3491+
3492+
3493+class UserNotValidatedError(CredentialsError):
3494+ """The user is not validated."""
3495
3496
3497 def handle_failures(msg):
3498@@ -108,20 +77,17 @@
3499 def inner(self, *a, **kw):
3500 """Call 'f' within a try-except block.
3501
3502- If any exception occurs, self.error_cb is called and the exception
3503- is logged.
3504+ If any exception occurs, the exception is logged and re-raised.
3505+
3506 """
3507 result = None
3508 try:
3509 result = yield f(self, *a, **kw)
3510- except Exception: # pylint: disable=W0703
3511+ except:
3512 logger.exception('%s (app_name: %s): %s.',
3513 f.__name__, self.app_name, msg)
3514- logger.error('%s (app_name: %s): Calling error_cb at %r.',
3515- f.__name__, self.app_name, self.error_cb)
3516- error_dict = {ERROR_KEY: msg,
3517- ERROR_DETAIL_KEY: traceback.format_exc()}
3518- self.error_cb(error_dict)
3519+ raise
3520+
3521 defer.returnValue(result)
3522
3523 return inner
3524@@ -133,14 +99,13 @@
3525 """Credentials management gateway."""
3526
3527 def __init__(self, app_name, tc_url=None, help_text='',
3528- window_id=0, ping_url=None,
3529- ui_module='ubuntu_sso.gtk.gui', ui_class='UbuntuSSOClientGUI',
3530- success_cb=NO_OP, error_cb=NO_OP, denial_cb=NO_OP):
3531+ window_id=0, ping_url=None, policy_url=None,
3532+ ui_executable=UI_EXECUTABLE_GTK):
3533 """Return a Credentials management object.
3534
3535 'app_name' is the application name to be displayed in the GUI.
3536
3537- 'tc_url' is the URL pointing to Terms & Conditions. If None, no
3538+ 'tc_url' is the url pointing to Terms & Conditions. If None, no
3539 TOS agreement will be displayed.
3540
3541 'help_text' is an explanatory text for the end-users, will be shown
3542@@ -152,9 +117,11 @@
3543 'ping_url' is the url that will be pinged when a user registers/logins
3544 successfully. The user email will be attached to 'ping_url'.
3545
3546- 'success_cb' will be called when the credentials were retrieved
3547- successfully. Two params will be passed: the app_name and the
3548- credentials per se. The credentials is a dictionary of the form:
3549+ 'policy_url' is the url pointing to the privacy policy. If None, no
3550+ privacy policy agreement will be displayed.
3551+
3552+ When the credentials are retrieved successfully, a dictionary like the
3553+ one below is returned:
3554
3555 {'token': <value>,
3556 'token_secret': <value>,
3557@@ -162,106 +129,44 @@
3558 'consumer_secret': <value>,
3559 'name': <the token name, matches "[app_name] @ [host name]">}
3560
3561- 'error_cb' will be called when the credentials retrieval failed. Two
3562- params will be passed: the app_name, and an error dict with 2 keys:
3563- the error message (user friendly, not translatable so far), and
3564- the detailed error (usually the traceback).
3565-
3566- 'denial_cb' will be called when the user denied the credentials to the
3567- caller. A single param is passed: the app_name.
3568-
3569 """
3570 self.app_name = app_name
3571 self.help_text = help_text
3572 self.window_id = window_id
3573 self.ping_url = ping_url
3574 self.tc_url = tc_url
3575- self.ui_module = ui_module
3576- self.ui_class = ui_class
3577- self._success_cb = success_cb
3578- self._error_cb = error_cb
3579- self.denial_cb = denial_cb
3580- self.inner = None # will hold the GUI or SSOLoginRoot instance
3581+ self.policy_url = policy_url
3582+ self.ui_executable = ui_executable
3583
3584- @handle_failures(msg='Problem while retrieving credentials')
3585 @defer.inlineCallbacks
3586- def _login_success_cb(self, app_name, email):
3587- """Store credentials when the login/registration succeeded.
3588-
3589- Also, open self.ping_url/email to notify about this new token. If any
3590- error occur, self.error_cb is called. Otherwise, self.success_cb is
3591- called.
3592-
3593- Return 0 on success, and a non-zero value (or None) on error.
3594-
3595- """
3596- logger.info('Login/registration was successful for app %r, email %r',
3597- app_name, email)
3598- creds = yield self.find_credentials()
3599- if creds is not None:
3600- assert len(creds) > 0, 'Creds are empty! This should not happen'
3601- # ping a server with the credentials if we were requested to
3602- if self.ping_url is not None:
3603- status = yield self._ping_url(app_name, email, creds)
3604- if status is None:
3605- yield self.clear_credentials()
3606- return
3607-
3608- self.success_cb(creds)
3609- defer.returnValue(0)
3610-
3611- def _auth_denial_cb(self, app_name):
3612- """The user decided not to allow the registration or login."""
3613- logger.warning('Login/registration was denied to app %r', app_name)
3614- self.denial_cb(app_name)
3615-
3616- @handle_failures(msg='Problem opening the ping_url')
3617- def _ping_url(self, app_name, email, credentials):
3618- """Ping the self.ping_url with the email attached.
3619-
3620- Sign the request with the user credentials. The self.ping_url must be
3621- defined if this method is being called.
3622-
3623- """
3624- logger.info('Pinging server for app_name %r, ping_url: %r, '
3625- 'email %r.', app_name, self.ping_url, email)
3626- try:
3627- url = self.ping_url.format(email=email)
3628- except IndexError: # tuple index out of range
3629- url = self.ping_url.format(email) # format the first substitution
3630-
3631- if url == self.ping_url:
3632- logger.debug('Original url (%r) could not be formatted, '
3633- 'appending email (%r).', self.ping_url, email)
3634- url = self.ping_url + email
3635-
3636- headers = utils.oauth_headers(url, credentials)
3637- request = urllib2.Request(url, headers=headers)
3638- logger.debug('Opening the url %r with urllib2.urlopen.',
3639- request.get_full_url())
3640- # This code is blocking, we should change this.
3641- # I've tried with deferToThread an twisted.web.client.getPage
3642- # but the returned deferred will never be fired (nataliabidart).
3643- response = urllib2.urlopen(request)
3644- logger.debug('Url opened. Response: %s.', response.code)
3645- return defer.succeed(response)
3646-
3647- @handle_exceptions(msg='Problem opening the Ubuntu SSO user interface')
3648 def _show_ui(self, login_only):
3649 """Shows the UI, connect outcome signals."""
3650-
3651- __import__(self.ui_module)
3652- gui = sys.modules[self.ui_module]
3653-
3654- self.inner = getattr(gui, self.ui_class)(app_name=self.app_name,
3655- tc_url=self.tc_url, help_text=self.help_text,
3656- window_id=self.window_id, login_only=login_only)
3657-
3658- self.inner.login_success_callback = self._login_success_cb
3659- self.inner.registration_success_callback = self._login_success_cb
3660- self.inner.user_cancellation_callback = self._auth_denial_cb
3661-
3662- @handle_exceptions(msg='Problem logging with email and password.')
3663+ ui_exe_path = os.path.join(get_bin_dir(), self.ui_executable)
3664+ args = [ui_exe_path]
3665+ for arg in ('app_name', 'help_text', 'ping_url', 'policy_url',
3666+ 'tc_url', 'window_id'):
3667+ value = getattr(self, arg)
3668+ if value:
3669+ args.append('--%s' % arg)
3670+ args.append("%s" % str(value))
3671+
3672+ if login_only:
3673+ args.append('--login_only')
3674+
3675+ return_code = yield runner.spawn_program(args)
3676+ logger.info('_show_ui: received from the ui return code %r.',
3677+ return_code)
3678+
3679+ credentials = None
3680+ if return_code == USER_SUCCESS:
3681+ credentials = yield self.find_credentials()
3682+ elif return_code == USER_CANCELLATION:
3683+ raise UserCancellationError()
3684+ else:
3685+ raise CredentialsError(return_code)
3686+
3687+ defer.returnValue(credentials)
3688+
3689 def _do_login(self, email, password):
3690 """Login using email/password, connect outcome signals."""
3691 from ubuntu_sso.main import SSOLogin
3692@@ -279,62 +184,43 @@
3693
3694 def LoginError(self, app_name, error):
3695 """There was an error on login."""
3696+ error = CredentialsError(error['errtype'])
3697 d.errback(error)
3698
3699 def UserNotValidated(self, app_name, email):
3700 """User is not validated."""
3701- d.callback(None)
3702+ d.errback(UserNotValidatedError(email))
3703
3704 # pylint: enable=C0103
3705
3706- self.inner = SSOLogin(proxy=DummyProxy())
3707- self.inner.login(app_name=self.app_name,
3708- email=email, password=password)
3709-
3710- def _success(result):
3711- """Check if 'result' is a valid token, and callback properly."""
3712- if result is not None:
3713- return self._login_success_cb(self.app_name, email)
3714- else:
3715- error_dict = {
3716- 'errtype': 'UserNotValidated',
3717- 'message': email,
3718- }
3719- self._error_cb(self.app_name, error_dict)
3720-
3721- d.addCallback(_success)
3722- d.addErrback(lambda f: self._error_cb(self.app_name, f.value))
3723-
3724- @handle_failures(msg='Problem while retrieving credentials')
3725+ inner = SSOLogin(proxy=DummyProxy())
3726+ inner.login(app_name=self.app_name,
3727+ email=email, password=password,
3728+ ping_url=self.ping_url)
3729+
3730+ d.addCallback(lambda _: self.find_credentials())
3731+ return d
3732+
3733 @defer.inlineCallbacks
3734 def _login_or_register(self, login_only, email=None, password=None):
3735- """Get credentials if found else prompt the GUI."""
3736+ """Get credentials if found else prompt the GUI.
3737+
3738+ Will return either the credentials, or will raise UserCancellationError
3739+ if the user aborted the operation when the UI was opened.
3740+
3741+ """
3742 logger.info("_login_or_register: login_only=%r email=%r.",
3743- login_only, email)
3744+ login_only, email)
3745 token = yield self.find_credentials()
3746- if token is not None and len(token) > 0:
3747- self.success_cb(token)
3748- elif token == {}:
3749+ if not token:
3750 if email and password:
3751- self._do_login(email, password)
3752+ token = yield self._do_login(email, password)
3753 else:
3754- self._show_ui(login_only)
3755- else:
3756- # something went wrong with find_credentials, already handled.
3757- logger.info('_login_or_register: call to "find_credentials" went '
3758- 'wrong, and was already handled.')
3759-
3760- def error_cb(self, error_dict):
3761- """Handle error and notify the caller."""
3762- logger.error('Calling error callback at %r (error is %r).',
3763- self._error_cb, error_dict)
3764- self._error_cb(self.app_name, error_dict)
3765-
3766- def success_cb(self, creds):
3767- """Handle success and notify the caller."""
3768- logger.debug('Calling success callback at %r.', self._success_cb)
3769- self._success_cb(self.app_name, creds)
3770-
3771+ token = yield self._show_ui(login_only)
3772+
3773+ defer.returnValue(token)
3774+
3775+ @handle_failures(msg='Problem while getting credentials from the keyring')
3776 @defer.inlineCallbacks
3777 def find_credentials(self):
3778 """Get the credentials for 'self.app_name'. Return {} if not there."""
3779@@ -343,20 +229,22 @@
3780 'result is {}? %s', self.app_name, creds is None)
3781 defer.returnValue(creds if creds is not None else {})
3782
3783- @defer.inlineCallbacks
3784+ @handle_failures(msg='Problem while clearing credentials in the keyring')
3785 def clear_credentials(self):
3786 """Clear the credentials for 'self.app_name'."""
3787- yield Keyring().delete_credentials(self.app_name)
3788+ return Keyring().delete_credentials(self.app_name)
3789
3790- @defer.inlineCallbacks
3791+ @handle_failures(msg='Problem while storing credentials in the keyring')
3792 def store_credentials(self, token):
3793 """Store the credentials for 'self.app_name'."""
3794- yield Keyring().set_credentials(self.app_name, token)
3795+ return Keyring().set_credentials(self.app_name, token)
3796
3797+ @handle_failures(msg='Problem while performing register')
3798 def register(self):
3799 """Get credentials if found else prompt the GUI to register."""
3800 return self._login_or_register(login_only=False)
3801
3802+ @handle_failures(msg='Problem while performing login')
3803 def login(self, email=None, password=None):
3804 """Get credentials if found else prompt the GUI to login.
3805
3806
3807=== modified file 'ubuntu_sso/gtk/__init__.py'
3808--- ubuntu_sso/gtk/__init__.py 2010-11-19 19:53:22 +0000
3809+++ ubuntu_sso/gtk/__init__.py 2012-02-14 22:04:20 +0000
3810@@ -1,8 +1,6 @@
3811 # -*- coding: utf-8 -*-
3812 #
3813-# Author: Natalia Bidart <natalia.bidart@canonical.com>
3814-#
3815-# Copyright 2009-2010 Canonical Ltd.
3816+# Copyright 2009-2012 Canonical Ltd.
3817 #
3818 # This program is free software: you can redistribute it and/or modify it
3819 # under the terms of the GNU General Public License version 3, as published
3820
3821=== modified file 'ubuntu_sso/gtk/gui.py'
3822--- ubuntu_sso/gtk/gui.py 2012-01-31 19:02:36 +0000
3823+++ ubuntu_sso/gtk/gui.py 2012-02-14 22:04:20 +0000
3824@@ -1,6 +1,6 @@
3825 # -*- coding: utf-8 -*-
3826 #
3827-# Copyright 2010 Canonical Ltd.
3828+# Copyright 2010-2012 Canonical Ltd.
3829 #
3830 # This program is free software: you can redistribute it and/or modify it
3831 # under the terms of the GNU General Public License version 3, as published
3832@@ -22,18 +22,23 @@
3833 import tempfile
3834 import webbrowser
3835
3836-from functools import wraps
3837-
3838-import gtk
3839-
3840+from functools import wraps, partial
3841+
3842+# pylint: disable=E0611,F0401
3843+from gi.repository import Gdk, Gtk
3844+from gi.repository.GdkX11 import X11Window
3845+# pylint: enable=E0611,F0401
3846 from twisted.internet import defer
3847
3848 from ubuntu_sso import (
3849 main,
3850 NO_OP,
3851+ USER_CANCELLATION,
3852+ USER_SUCCESS,
3853 utils,
3854 )
3855-from ubuntu_sso.logger import setup_logging
3856+from ubuntu_sso.logger import setup_gui_logging
3857+from ubuntu_sso.utils import get_data_file
3858 from ubuntu_sso.utils.ui import (
3859 CAPTCHA_LOAD_ERROR,
3860 CAPTCHA_RELOAD_TOOLTIP,
3861@@ -43,7 +48,7 @@
3862 ERROR,
3863 FIELD_REQUIRED,
3864 FORGOTTEN_PASSWORD_BUTTON,
3865- get_data_file,
3866+ GENERIC_BACKEND_ERROR,
3867 is_min_required_password,
3868 is_correct_email,
3869 JOIN_HEADER_LABEL,
3870@@ -72,7 +77,19 @@
3871 # pylint: disable=E1101
3872
3873
3874-logger = setup_logging('ubuntu_sso.gui')
3875+logger = setup_gui_logging('ubuntu_sso.gui.gtk')
3876+
3877+
3878+# pylint: disable=C0103
3879+def parse_color(color):
3880+ """Parse a string color into Gdk.Color."""
3881+ c = Gdk.RGBA()
3882+ result = c.parse(color)
3883+ if not result:
3884+ logger.warning('Could not parse color %r.', color)
3885+ return c
3886+# pylint: enable=C0103
3887+
3888
3889 # To be removed when Python bindings provide these constants
3890 # as per http://code.google.com/p/pywebkitgtk/issues/detail?id=44
3891@@ -92,11 +109,8 @@
3892
3893 DEFAULT_WIDTH = 30
3894 # To be replaced by values from the theme (LP: #616526)
3895-HELP_TEXT_COLOR = gtk.gdk.Color("#bfbfbf")
3896-WARNING_TEXT_COLOR = gtk.gdk.Color("red")
3897-
3898-USER_CANCELLATION = 10
3899-LOGIN_SUCCESS = REGISTRATION_SUCCESS = 0
3900+HELP_TEXT_COLOR = parse_color("#bfbfbf")
3901+WARNING_TEXT_COLOR = parse_color("red")
3902
3903
3904 def log_call(f):
3905@@ -111,9 +125,12 @@
3906 return inner
3907
3908
3909-class LabeledEntry(gtk.Entry):
3910+class LabeledEntry(Gtk.Entry):
3911 """An entry that displays the label within itself ina grey color."""
3912
3913+ # Use of super on an old style class
3914+ # pylint: disable=E1002
3915+
3916 def __init__(self, label, is_password=False, *args, **kwargs):
3917 self.label = label
3918 self.is_password = is_password
3919@@ -133,7 +150,8 @@
3920 """Clear text and restore text color."""
3921 self.set_text(self.get_text())
3922
3923- self.modify_text(gtk.STATE_NORMAL, None) # restore to theme's default
3924+ # restore to theme's default
3925+ self.override_color(Gtk.StateFlags.NORMAL, None)
3926
3927 if self.is_password:
3928 self.set_visibility(False)
3929@@ -146,7 +164,7 @@
3930 return
3931
3932 self.set_text(self.label)
3933- self.modify_text(gtk.STATE_NORMAL, HELP_TEXT_COLOR)
3934+ self.override_color(Gtk.StateFlags.NORMAL, HELP_TEXT_COLOR)
3935
3936 if self.is_password:
3937 self.set_visibility(True)
3938@@ -163,7 +181,7 @@
3939 def set_warning(self, warning_msg):
3940 """Display warning as secondary icon, set 'warning_msg' as tooltip."""
3941 self.warning = warning_msg
3942- self.set_property('secondary-icon-stock', gtk.STOCK_DIALOG_WARNING)
3943+ self.set_property('secondary-icon-stock', Gtk.STOCK_DIALOG_WARNING)
3944 self.set_property('secondary-icon-sensitive', True)
3945 self.set_property('secondary-icon-activatable', False)
3946 self.set_property('secondary-icon-tooltip-text', warning_msg)
3947@@ -185,8 +203,6 @@
3948 logger.debug('UbuntuSSOClientGUI: app_name %r, kwargs %r.',
3949 app_name, kwargs)
3950
3951- gtk.link_button_set_uri_hook(NO_OP)
3952-
3953 self._captcha_filename = tempfile.mktemp()
3954 self._captcha_id = None
3955 self._signals_receivers = {}
3956@@ -201,29 +217,22 @@
3957 window_id = kwargs.get('window_id', 0)
3958 self.close_callback = kwargs.get('close_callback', NO_OP)
3959 self.backend = None
3960- # the following 3 callbacks will be removed as soon as
3961- # the backend stop using them
3962- self.login_success_callback = NO_OP
3963- self.registration_success_callback = NO_OP
3964- self.user_cancellation_callback = NO_OP
3965-
3966 self.user_email = None
3967 self.user_password = None
3968
3969 ui_filename = get_data_file('gtk', 'ui.glade')
3970- builder = gtk.Builder()
3971+ builder = Gtk.Builder()
3972 builder.add_from_file(ui_filename)
3973 builder.connect_signals(self)
3974
3975 self.widgets = []
3976 self.warnings = []
3977 self.cancels = []
3978- self.labels = []
3979 for obj in builder.get_objects():
3980 name = getattr(obj, 'name', None)
3981- if name is None and isinstance(obj, gtk.Buildable):
3982+ if name is None and isinstance(obj, Gtk.Buildable):
3983 # work around bug lp:507739
3984- name = gtk.Buildable.get_name(obj)
3985+ name = Gtk.Buildable.get_name(obj)
3986 if name is None:
3987 logging.warn("%s has no name (??)", obj)
3988 else:
3989@@ -235,9 +244,12 @@
3990 if 'cancel_button' in name:
3991 obj.connect('clicked', self.on_close_clicked)
3992 self.cancels.append(obj)
3993- if 'label' in name:
3994- obj.connect('size-allocate', self.on_size_allocate)
3995- self.labels.append(obj)
3996+
3997+ # Connect the activate-link signal here
3998+ # GtkBuilder in GTK 3 seems to not do this
3999+ self.login_button.connect('activate-link', self.on_activate_link)
4000+ self.forgotten_password_button.connect('activate-link',
4001+ self.on_activate_link)
4002
4003 self.entries = (u'name_entry', u'email1_entry', u'email2_entry',
4004 u'password1_entry', u'password2_entry',
4005@@ -297,7 +309,10 @@
4006 # still do everything as a standalone window. Also,
4007 # window_foreign_new may return None breaking set_transient_for.
4008 try:
4009- win = gtk.gdk.window_foreign_new(window_id)
4010+ display = Gdk.Display.get_default()
4011+ # this is not working, we need to create a XLib.window
4012+ # as a second parameter to foreign_new_for_display
4013+ win = X11Window.foreign_new_for_display(display, None)
4014 self.window.realize()
4015 self.window.window.set_transient_for(win)
4016 except: # pylint: disable=W0702
4017@@ -366,20 +381,21 @@
4018
4019 def _add_spinner_to_container(self, container, legend=None):
4020 """Add a spinner to 'container'."""
4021- spinner = gtk.Spinner()
4022+ spinner = Gtk.Spinner()
4023 spinner.start()
4024
4025- label = gtk.Label()
4026+ label = Gtk.Label()
4027 if legend:
4028 label.set_text(legend)
4029 else:
4030 label.set_text(LOADING)
4031
4032- hbox = gtk.HBox(spacing=5)
4033- hbox.pack_start(spinner, expand=False)
4034- hbox.pack_start(label, expand=False)
4035+ hbox = Gtk.HBox(spacing=5)
4036+ hbox.pack_start(spinner, expand=False, fill=True, padding=0)
4037+ hbox.pack_start(label, expand=False, fill=True, padding=0)
4038
4039- alignment = gtk.Alignment(xalign=0.5, yalign=0.5)
4040+ alignment = Gtk.Alignment(xalign=0.5, yalign=0.5,
4041+ xscale=0, yscale=0)
4042 alignment.add(hbox)
4043 alignment.show_all()
4044
4045@@ -394,7 +410,7 @@
4046 def _set_warning_message(self, widget, message):
4047 """Set 'message' as text for 'widget'."""
4048 widget.set_text(message)
4049- widget.modify_fg(gtk.STATE_NORMAL, WARNING_TEXT_COLOR)
4050+ widget.override_color(Gtk.StateFlags.NORMAL, WARNING_TEXT_COLOR)
4051 widget.show()
4052
4053 def _clear_warnings(self):
4054@@ -409,6 +425,12 @@
4055 text = widget.get_text()
4056 return bool(text and not text.isspace())
4057
4058+ def _handle_error(self, remote_call, handler, error):
4059+ """Handle any error when calling the remote backend."""
4060+ logger.error('Remote call %r failed with: %r', remote_call, error)
4061+ errordict = {'message': GENERIC_BACKEND_ERROR}
4062+ handler(self.app_name, errordict)
4063+
4064 # build pages
4065
4066 def _append_pages(self):
4067@@ -433,7 +455,7 @@
4068
4069 def _append_page(self, page):
4070 """Append 'page' to the 'window'."""
4071- self.content.append_page(page)
4072+ self.content.append_page(page, None)
4073
4074 def _set_header(self, header):
4075 """Set 'header' as the window title and header."""
4076@@ -464,16 +486,19 @@
4077 logger.info('Calling generate_captcha with filename path at %r',
4078 self._captcha_filename)
4079 self.warning_label.set_text('')
4080- self.backend.generate_captcha(self.app_name, self._captcha_filename,
4081- reply_handler=NO_OP, error_handler=NO_OP)
4082+ f = self.backend.generate_captcha
4083+ error_handler = partial(self._handle_error, f,
4084+ self.on_captcha_generation_error)
4085+ f(self.app_name, self._captcha_filename,
4086+ reply_handler=NO_OP, error_handler=error_handler)
4087 self._set_captcha_loading()
4088
4089 def _set_captcha_loading(self):
4090 """Present a spinner to the user while the captcha is downloaded."""
4091 self.captcha_image.hide()
4092 self._add_spinner_to_container(self.captcha_loading)
4093- white = gtk.gdk.Color('white')
4094- self.captcha_loading.modify_bg(gtk.STATE_NORMAL, white)
4095+ self.captcha_loading.override_background_color(Gtk.StateFlags.NORMAL,
4096+ parse_color('white'))
4097 self.captcha_loading.show_all()
4098 self.join_ok_button.set_sensitive(False)
4099
4100@@ -490,20 +515,26 @@
4101 self.enter_details_vbox.header = JOIN_HEADER_LABEL % d
4102 self.enter_details_vbox.help_text = self.help_text
4103 self.enter_details_vbox.default_widget = self.join_ok_button
4104- self.join_ok_button.set_flags(gtk.CAN_DEFAULT)
4105+ self.join_ok_button.set_can_default(True)
4106
4107- self.enter_details_vbox.pack_start(self.name_entry, expand=False)
4108+ self.enter_details_vbox.pack_start(self.name_entry,
4109+ expand=False, fill=True, padding=0)
4110 self.enter_details_vbox.reorder_child(self.name_entry, 0)
4111 entry = self.captcha_solution_entry
4112- self.captcha_solution_vbox.pack_start(entry, expand=False)
4113+ self.captcha_solution_vbox.pack_start(entry,
4114+ expand=False, fill=True, padding=0)
4115 msg = CAPTCHA_RELOAD_TOOLTIP
4116 self.captcha_reload_button.set_tooltip_text(msg)
4117
4118- self.emails_hbox.pack_start(self.email1_entry, expand=False)
4119- self.emails_hbox.pack_start(self.email2_entry, expand=False)
4120+ self.emails_hbox.pack_start(self.email1_entry,
4121+ expand=False, fill=True, padding=0)
4122+ self.emails_hbox.pack_start(self.email2_entry,
4123+ expand=False, fill=True, padding=0)
4124
4125- self.passwords_hbox.pack_start(self.password1_entry, expand=False)
4126- self.passwords_hbox.pack_start(self.password2_entry, expand=False)
4127+ self.passwords_hbox.pack_start(self.password1_entry,
4128+ expand=False, fill=True, padding=0)
4129+ self.passwords_hbox.pack_start(self.password2_entry,
4130+ expand=False, fill=True, padding=0)
4131 help_msg = '<small>%s</small>' % PASSWORD_HELP
4132 self.password_help_label.set_markup(help_msg)
4133
4134@@ -519,7 +550,7 @@
4135 self.yes_to_tc_checkbutton.set_label(msg)
4136 self.tc_button.set_label(TC_BUTTON)
4137 else:
4138- self.tc_vbox.hide_all()
4139+ self.tc_vbox.hide()
4140 self.login_button.set_label(LOGIN_BUTTON_LABEL)
4141
4142 return self.enter_details_vbox
4143@@ -528,7 +559,7 @@
4144 """Build the Terms & Conditions page."""
4145 self.tc_browser_vbox.help_text = ''
4146 self.tc_browser_vbox.default_widget = self.tc_back_button
4147- self.tc_browser_vbox.default_widget.set_flags(gtk.CAN_DEFAULT)
4148+ self.tc_browser_vbox.default_widget.set_can_default(True)
4149 return self.tc_browser_vbox
4150
4151 def _build_processing_page(self):
4152@@ -541,17 +572,16 @@
4153 def _build_verify_email_page(self):
4154 """Build the verify email page."""
4155 self.verify_email_vbox.default_widget = self.verify_token_button
4156- self.verify_email_vbox.default_widget.set_flags(gtk.CAN_DEFAULT)
4157+ self.verify_email_vbox.default_widget.set_can_default(True)
4158
4159 self.verify_email_details_vbox.pack_start(self.email_token_entry,
4160- expand=False)
4161-
4162+ expand=False, fill=True, padding=0)
4163 return self.verify_email_vbox
4164
4165 def _build_finish_page(self):
4166 """Build the success page."""
4167 self.finish_vbox.default_widget = self.finish_close_button
4168- self.finish_vbox.default_widget.set_flags(gtk.CAN_DEFAULT)
4169+ self.finish_vbox.default_widget.set_can_default(True)
4170 self.finish_vbox.label = self.finish_label
4171 return self.finish_vbox
4172
4173@@ -561,11 +591,13 @@
4174 self.login_vbox.header = LOGIN_HEADER_LABEL % d
4175 self.login_vbox.help_text = CONNECT_HELP_LABEL % d
4176 self.login_vbox.default_widget = self.login_ok_button
4177- self.login_vbox.default_widget.set_flags(gtk.CAN_DEFAULT)
4178+ self.login_vbox.default_widget.set_can_default(True)
4179
4180- self.login_details_vbox.pack_start(self.login_email_entry)
4181+ self.login_details_vbox.pack_start(self.login_email_entry,
4182+ expand=True, fill=True, padding=0)
4183 self.login_details_vbox.reorder_child(self.login_email_entry, 0)
4184- self.login_details_vbox.pack_start(self.login_password_entry)
4185+ self.login_details_vbox.pack_start(self.login_password_entry,
4186+ expand=True, fill=True, padding=0)
4187 self.login_details_vbox.reorder_child(self.login_password_entry, 1)
4188
4189 msg = FORGOTTEN_PASSWORD_BUTTON
4190@@ -580,12 +612,12 @@
4191 text = REQUEST_PASSWORD_TOKEN_LABEL % {'app_name': self.app_label}
4192 self.request_password_token_vbox.help_text = text
4193 btn = self.request_password_token_ok_button
4194- btn.set_flags(gtk.CAN_DEFAULT)
4195+ btn.set_can_default(True)
4196 self.request_password_token_vbox.default_widget = btn
4197
4198 entry = self.reset_email_entry
4199 self.request_password_token_details_vbox.pack_start(entry,
4200- expand=False)
4201+ expand=False, fill=True, padding=0)
4202 cb = self.on_reset_email_entry_changed
4203 self.reset_email_entry.connect('changed', cb)
4204 self.request_password_token_ok_button.set_label(NEXT)
4205@@ -598,13 +630,14 @@
4206 self.set_new_password_vbox.header = RESET_PASSWORD
4207 self.set_new_password_vbox.help_text = SET_NEW_PASSWORD_LABEL
4208 btn = self.set_new_password_ok_button
4209- btn.set_flags(gtk.CAN_DEFAULT)
4210+ btn.set_can_default(True)
4211 self.set_new_password_vbox.default_widget = btn
4212
4213 for entry in (self.reset_code_entry,
4214 self.reset_password1_entry,
4215 self.reset_password2_entry):
4216- self.set_new_password_details_vbox.pack_start(entry, expand=False)
4217+ self.set_new_password_details_vbox.pack_start(entry,
4218+ expand=False, fill=True, padding=0)
4219
4220 cb = self.on_set_new_password_entries_changed
4221 self.reset_code_entry.connect('changed', cb)
4222@@ -645,6 +678,11 @@
4223
4224 # GTK callbacks
4225
4226+ def destroy(self):
4227+ """Destroy this UI."""
4228+ self.window.hide()
4229+ self.window.destroy()
4230+
4231 def connect(self, signal_name, handler, *args, **kwargs):
4232 """Connect 'signal_name' with 'handler'."""
4233 logger.debug('connect: signal %r, handler %r, args %r, kwargs, %r',
4234@@ -661,9 +699,9 @@
4235 self._done = True
4236 self._set_current_page(self.error_vbox)
4237
4238- def on_size_allocate(self, widget, allocation):
4239- """The widget can re rezised, embrase it!."""
4240- widget.set_size_request(allocation.width - 2, -1)
4241+ def on_activate_link(self, button):
4242+ """Do nothing, used for LinkButtons that are used as regular ones."""
4243+ return True
4244
4245 def on_close_clicked(self, *args, **kwargs):
4246 """Call self.close_callback if defined."""
4247@@ -678,16 +716,16 @@
4248 self.window.hide()
4249
4250 # process any pending events before callbacking with result
4251- while gtk.events_pending():
4252- gtk.main_iteration()
4253+ while Gtk.events_pending():
4254+ Gtk.main_iteration()
4255
4256- return_code = LOGIN_SUCCESS
4257+ return_code = USER_SUCCESS
4258 if not self._done:
4259- self.user_cancellation_callback(self.app_name)
4260 return_code = USER_CANCELLATION
4261+ logger.info('Return code will be %r.', return_code)
4262
4263 # call user defined callback
4264- logger.info('Calling custom close_callback %r with params %r, %r',
4265+ logger.debug('Calling custom close_callback %r with params %r, %r',
4266 self.close_callback, args, kwargs)
4267 self.close_callback(*args, **kwargs)
4268
4269@@ -750,10 +788,14 @@
4270 logger.info('Calling register_user with email %r, password <hidden>,' \
4271 ' name %r, captcha_id %r and captcha_solution %r.', email1,
4272 name, self._captcha_id, captcha_solution)
4273+
4274 f = self.backend.register_user
4275- f(self.app_name, email1, password1, name,
4276- self._captcha_id, captcha_solution,
4277- reply_handler=NO_OP, error_handler=NO_OP)
4278+ error_handler = partial(self._handle_error, f,
4279+ self.on_user_registration_error)
4280+ f(unicode(self.app_name), email1.decode('utf8'),
4281+ password1.decode('utf8'), name.decode('utf8'),
4282+ unicode(self._captcha_id), captcha_solution.decode('utf8'),
4283+ reply_handler=NO_OP, error_handler=error_handler)
4284
4285 def on_verify_token_button_clicked(self, *args, **kwargs):
4286 """The user entered the email token, let's verify!"""
4287@@ -772,7 +814,7 @@
4288
4289 args = (self.app_name, email, password, email_token)
4290 if self.ping_url:
4291- f = self.backend.validate_email_with_ping
4292+ f = self.backend.validate_email_and_ping
4293 args = args + (self.ping_url,)
4294 else:
4295 f = self.backend.validate_email
4296@@ -780,7 +822,9 @@
4297 logger.info('Calling validate_email with email %r, password <hidden>, '
4298 'app_name %r and email_token %r.', email, self.app_name,
4299 email_token)
4300- f(*args, reply_handler=NO_OP, error_handler=NO_OP)
4301+ error_handler = partial(self._handle_error, f,
4302+ self.on_email_validation_error)
4303+ f(*args, reply_handler=NO_OP, error_handler=error_handler)
4304
4305 self._set_current_page(self.processing_vbox)
4306
4307@@ -809,12 +853,13 @@
4308
4309 args = (self.app_name, email, password)
4310 if self.ping_url:
4311- f = self.backend.login_with_ping
4312+ f = self.backend.login_and_ping
4313 args = args + (self.ping_url,)
4314 else:
4315 f = self.backend.login
4316
4317- f(*args, reply_handler=NO_OP, error_handler=NO_OP)
4318+ error_handler = partial(self._handle_error, f, self.on_login_error)
4319+ f(*args, reply_handler=NO_OP, error_handler=error_handler)
4320
4321 self._set_current_page(self.processing_vbox)
4322 self.user_email = email
4323@@ -843,7 +888,10 @@
4324
4325 logger.info('Calling request_password_reset_token with %r.', email)
4326 f = self.backend.request_password_reset_token
4327- f(self.app_name, email, reply_handler=NO_OP, error_handler=NO_OP)
4328+ error_handler = partial(self._handle_error, f,
4329+ self.on_password_reset_error)
4330+ f(self.app_name, email,
4331+ reply_handler=NO_OP, error_handler=error_handler)
4332
4333 self._set_current_page(self.processing_vbox)
4334
4335@@ -894,16 +942,18 @@
4336 logger.info('Calling set_new_password with email %r, token %r and ' \
4337 'new password: <hidden>.', email, token)
4338 f = self.backend.set_new_password
4339+ error_handler = partial(self._handle_error, f,
4340+ self.on_password_change_error)
4341 f(self.app_name, email, token, password1,
4342- reply_handler=NO_OP, error_handler=NO_OP)
4343+ reply_handler=NO_OP, error_handler=error_handler)
4344
4345 self._set_current_page(self.processing_vbox)
4346
4347 def on_tc_button_clicked(self, *args, **kwargs):
4348 """The T&C button was clicked, create the browser and load terms."""
4349 # delay the import of webkit to be able to build without it
4350- import webkit
4351- browser = webkit.WebView()
4352+ from gi.repository import WebKit # pylint: disable=E0611
4353+ browser = WebKit.WebView()
4354
4355 # The signal WebKitWebView::load-finished is deprecated and should not
4356 # be used in newly-written code. Use the "load-status" property
4357@@ -1023,7 +1073,6 @@
4358 @log_call
4359 def on_email_validated(self, app_name, email, *args, **kwargs):
4360 """User email was successfully verified."""
4361- self.registration_success_callback(self.app_name, email)
4362 self.finish_success()
4363
4364 @log_call
4365@@ -1039,7 +1088,6 @@
4366 @log_call
4367 def on_logged_in(self, app_name, email, *args, **kwargs):
4368 """User was successfully logged in."""
4369- self.login_success_callback(self.app_name, email)
4370 self.finish_success()
4371
4372 @log_call
4373
4374=== modified file 'ubuntu_sso/gtk/main.py'
4375--- ubuntu_sso/gtk/main.py 2012-01-16 21:10:12 +0000
4376+++ ubuntu_sso/gtk/main.py 2012-02-14 22:04:20 +0000
4377@@ -16,34 +16,14 @@
4378
4379 """Main module to open the GTK UI."""
4380
4381-import argparse
4382-
4383-import gtk
4384+# pylint: disable=E0611
4385+from gi.repository import Gtk
4386+# pylint: enable=E0611
4387
4388 from ubuntu_sso.gtk.gui import UbuntuSSOClientGUI
4389
4390
4391-def parse_args():
4392- """Parse sys.argv options."""
4393- parser = argparse.ArgumentParser(description='Open the GTK SSO UI.')
4394- parser.add_argument('--app_name', required=True,
4395- help='the name of the application to retrieve credentials for')
4396- parser.add_argument('--ping_url', default='',
4397- help='a link to be used as the ping url (to notify about new tokens)')
4398- parser.add_argument('--tc_url', default='',
4399- help='a link to be used as Terms & Conditions url')
4400- parser.add_argument('--help_text', default='',
4401- help='extra text that will be shown below the headers')
4402- parser.add_argument('--window_id', type=int, default=0,
4403- help='the window id to be set transient for the SSO GTK dialogs')
4404- parser.add_argument('--login_only', action='store_true', default=False,
4405- help='whether the SSO GTK UI should only offer login or not')
4406-
4407- args = parser.parse_args()
4408- return args
4409-
4410-
4411 def main(**kwargs):
4412 """Start the GTK mainloop and open the main window."""
4413- UbuntuSSOClientGUI(close_callback=gtk.main_quit, **kwargs)
4414- gtk.main()
4415+ UbuntuSSOClientGUI(close_callback=Gtk.main_quit, **kwargs)
4416+ Gtk.main()
4417
4418=== modified file 'ubuntu_sso/gtk/tests/__init__.py'
4419--- ubuntu_sso/gtk/tests/__init__.py 2010-11-19 19:53:22 +0000
4420+++ ubuntu_sso/gtk/tests/__init__.py 2012-02-14 22:04:20 +0000
4421@@ -1,8 +1,6 @@
4422 # -*- coding: utf-8 -*-
4423 #
4424-# Author: Natalia Bidart <natalia.bidart@canonical.com>
4425-#
4426-# Copyright 2009 Canonical Ltd.
4427+# Copyright 2009-2012 Canonical Ltd.
4428 #
4429 # This program is free software: you can redistribute it and/or modify it
4430 # under the terms of the GNU General Public License version 3, as published
4431
4432=== modified file 'ubuntu_sso/gtk/tests/test_gui.py'
4433--- ubuntu_sso/gtk/tests/test_gui.py 2012-01-31 19:02:36 +0000
4434+++ ubuntu_sso/gtk/tests/test_gui.py 2012-02-14 22:04:20 +0000
4435@@ -21,8 +21,9 @@
4436
4437 from collections import defaultdict
4438
4439-import gtk
4440-import webkit
4441+# pylint: disable=E0611
4442+from gi.repository import Gdk, Gtk, WebKit
4443+# pylint: enable=E0611
4444
4445 from twisted.internet import defer
4446 from twisted.trial.unittest import TestCase
4447@@ -42,6 +43,9 @@
4448 # Instance of 'UbuntuSSOClientGUI' has no 'yyy' member
4449 # pylint: disable=E1101,E1103
4450
4451+# Use of super on an old style class
4452+# pylint: disable=E1002
4453+
4454
4455 class FakedSSOBackend(object):
4456 """Fake a SSO Backend."""
4457@@ -52,9 +56,9 @@
4458 self._called = {}
4459 self.callbacks = defaultdict(list)
4460
4461- for i in ('generate_captcha', 'login', 'login_with_ping',
4462+ for i in ('generate_captcha', 'login', 'login_and_ping',
4463 'register_user', 'validate_email',
4464- 'validate_email_with_ping',
4465+ 'validate_email_and_ping',
4466 'request_password_reset_token',
4467 'set_new_password'):
4468 setattr(self, i, self._record_call(i))
4469@@ -99,7 +103,7 @@
4470 self[prop_name] = newval
4471
4472
4473-class FakedEmbeddedBrowser(gtk.TextView):
4474+class FakedEmbeddedBrowser(Gtk.TextView):
4475 """Faked an embedded browser."""
4476
4477 def __init__(self):
4478@@ -156,6 +160,29 @@
4479 """Set _called to True."""
4480 self._called = (args, kwargs)
4481
4482+ def assert_color_equal(self, rgba_color, gdk_color):
4483+ """Check that 'rgba_color' is the same as 'gdk_color'."""
4484+ tmp = Gdk.RGBA()
4485+ assert tmp.parse(gdk_color.to_string())
4486+
4487+ msg = 'Text color must be "%s" (got "%s" instead).'
4488+ self.assertEqual(rgba_color, tmp, msg % (rgba_color, tmp))
4489+
4490+ def assert_backend_called(self, method, *args, **kwargs):
4491+ """Check that 'method(*args, **kwargs)' was called in the backend."""
4492+ self.assertIn(method, self.ui.backend._called)
4493+
4494+ call = self.ui.backend._called[method]
4495+ self.assertEqual(call[0], args)
4496+
4497+ reply_handler = call[1].pop('reply_handler')
4498+ self.assertEqual(reply_handler, gui.NO_OP)
4499+
4500+ error_handler = call[1].pop('error_handler')
4501+ self.assertEqual(error_handler.func, self.ui._handle_error)
4502+
4503+ self.assertEqual(call[1], kwargs)
4504+
4505
4506 class LabeledEntryTestCase(BasicTestCase):
4507 """Test suite for the labeled entry."""
4508@@ -168,9 +195,11 @@
4509 self.entry = gui.LabeledEntry(label=self.label)
4510
4511 # we need a window to be able to realize ourselves
4512- window = gtk.Window()
4513+ window = Gtk.Window()
4514 window.add(self.entry)
4515 window.show_all()
4516+ self.addCleanup(window.hide)
4517+ self.addCleanup(window.destroy)
4518
4519 def grab_focus(self, focus_in=True):
4520 """Grab focus on widget, if None use self.entry."""
4521@@ -188,10 +217,9 @@
4522 self.assertEqual(expected, actual, msg % (expected, actual))
4523
4524 # text color is correct
4525- msg = 'Text color must be "%s" (got "%s" instead).'
4526 expected = gui.HELP_TEXT_COLOR
4527- actual = self.entry.style.text[gtk.STATE_NORMAL]
4528- self.assertEqual(expected, actual, msg % (expected, actual))
4529+ actual = self.entry.get_style().text[Gtk.StateFlags.NORMAL]
4530+ self.assert_color_equal(expected, actual)
4531
4532 def test_initial_text(self):
4533 """Entry have the correct text at startup."""
4534@@ -218,11 +246,11 @@
4535
4536 def test_text_defaults_to_theme_color_when_focus_in(self):
4537 """Entry restore its text color when focused in."""
4538- self.patch(self.entry, 'modify_text', self._set_called)
4539+ self.patch(self.entry, 'override_color', self._set_called)
4540
4541 self.grab_focus()
4542
4543- self.assertEqual(((gtk.STATE_NORMAL, None), {}), self._called,
4544+ self.assertEqual(((Gtk.StateFlags.NORMAL, None), {}), self._called,
4545 'Entry text color must be restore on focus in.')
4546
4547 def test_refill_entry_on_focus_out_if_no_input(self):
4548@@ -305,7 +333,7 @@
4549 self.entry.set_warning(msg)
4550 self.assertEqual(self.entry.warning, msg)
4551 self.assertEqual(self.entry.get_property('secondary-icon-stock'),
4552- gtk.STOCK_DIALOG_WARNING)
4553+ Gtk.STOCK_DIALOG_WARNING)
4554 self.assertEqual(self.entry.get_property('secondary-icon-sensitive'),
4555 True)
4556 self.assertEqual(self.entry.get_property('secondary-icon-activatable'),
4557@@ -371,6 +399,7 @@
4558 'tc_browser', 'login', 'request_password_token',
4559 'set_new_password')
4560 self.ui = self.gui_class(**self.kwargs)
4561+ self.addCleanup(self.ui.destroy)
4562 self.error = {'message': UNKNOWN_ERROR}
4563
4564 def assert_entries_are_packed_to_ui(self, container_name, entries):
4565@@ -405,8 +434,8 @@
4566
4567 # content color is correct
4568 expected = gui.WARNING_TEXT_COLOR
4569- actual = label.style.fg[gtk.STATE_NORMAL]
4570- self.assertEqual(expected, actual) # until realized this will fail
4571+ actual = label.get_style().fg[Gtk.StateFlags.NORMAL]
4572+ self.assert_color_equal(expected, actual)
4573
4574 def assert_correct_entry_warning(self, entry, message):
4575 """Check that a warning is shown displaying 'message'."""
4576@@ -533,16 +562,6 @@
4577 entry = getattr(self.ui, name)
4578 self.assertTrue(entry.get_activates_default(), msg % (name,))
4579
4580- def test_label_size_allocated_is_connected(self):
4581- """Labels have the size-allocate signal connected."""
4582- msg = 'Label %r must have size-allocate connected.'
4583- labels = [i for i in self.ui.widgets if 'label' in i]
4584- for label in labels:
4585- widget = getattr(self.ui, label)
4586- widget.emit('size-allocate', gtk.gdk.Rectangle(1, 2, 3, 4))
4587- self.assertEqual(widget.get_size_request(), (3 - 2, -1),
4588- msg % (label,))
4589-
4590 def test_password_fields_are_password(self):
4591 """Password fields have the is_password flag set."""
4592 msg = '"%s" should be a password LabeledEntry instance.'
4593@@ -573,28 +592,6 @@
4594 """Main window has the proper icon."""
4595 self.assertEqual('ubuntu-logo', self.ui.window.get_icon_name())
4596
4597- def test_transient_window_is_none_if_window_id_is_zero(self):
4598- """The transient window is correct."""
4599- self.patch(gtk.gdk, 'window_foreign_new', self._set_called)
4600- self.gui_class(window_id=0, **self.kwargs)
4601- self.assertFalse(self._called, 'set_transient_for must not be called.')
4602-
4603- def test_transient_window_is_correct(self):
4604- """The transient window is correct."""
4605- xid = 5
4606- self.patch(gtk.gdk, 'window_foreign_new', self._set_called)
4607- self.gui_class(window_id=xid, **self.kwargs)
4608- self.assertTrue(self.memento.check(logging.ERROR, 'set_transient_for'))
4609- self.assertTrue(self.memento.check(logging.ERROR, str(xid)))
4610- self.assertEqual(self._called, ((xid,), {}))
4611-
4612- def test_transient_window_accepts_negative_id(self):
4613- """The transient window accepts a negative window id."""
4614- xid = -5
4615- self.patch(gtk.gdk, 'window_foreign_new', self._set_called)
4616- self.gui_class(window_id=xid, **self.kwargs)
4617- self.assertEqual(self._called, ((xid,), {}))
4618-
4619 def test_finish_success_shows_success_page(self):
4620 """When calling 'finish_success' the success page is shown."""
4621 self.ui.finish_success()
4622@@ -611,6 +608,42 @@
4623 self.assertEqual(gui.ERROR, self.ui.finish_vbox.label.get_text())
4624
4625
4626+class SetTransientForTestCase(UbuntuSSOClientTestCase):
4627+ """Test suite for setting the window as transient for another one."""
4628+
4629+ def test_transient_window_is_none_if_window_id_is_zero(self):
4630+ """The transient window is correct."""
4631+ self.patch(gui.X11Window, 'foreign_new_for_display', self._set_called)
4632+ ui = self.gui_class(window_id=0, **self.kwargs)
4633+ self.addCleanup(ui.destroy)
4634+
4635+ self.assertFalse(self._called, 'set_transient_for must not be called.')
4636+
4637+ def test_transient_window_is_correct(self):
4638+ """The transient window is correct."""
4639+ xid = 5
4640+ self.patch(gui.X11Window, 'foreign_new_for_display', self._set_called)
4641+ ui = self.gui_class(window_id=xid, **self.kwargs)
4642+ self.addCleanup(ui.destroy)
4643+
4644+ self.assertTrue(self.memento.check(logging.ERROR, 'set_transient_for'))
4645+ self.assertTrue(self.memento.check(logging.ERROR, str(xid)))
4646+ self.assertEqual(self._called, ((xid,), {}))
4647+
4648+ def test_transient_window_accepts_negative_id(self):
4649+ """The transient window accepts a negative window id."""
4650+ xid = -5
4651+ self.patch(gui.X11Window, 'foreign_new_for_display', self._set_called)
4652+ ui = self.gui_class(window_id=xid, **self.kwargs)
4653+ self.addCleanup(ui.destroy)
4654+
4655+ self.assertEqual(self._called, ((xid,), {}))
4656+
4657+
4658+SetTransientForTestCase.skip = "Apparently, so far we can't use XLib " \
4659+"dynamic bindings to complete the call to X11Window.foreign_new_for_display."
4660+
4661+
4662 class EnterDetailsTestCase(UbuntuSSOClientTestCase):
4663 """Test suite for the user registration (enter details page)."""
4664
4665@@ -670,13 +703,8 @@
4666 self.click_join_with_valid_data()
4667
4668 # assert register_user was called
4669- expected = 'register_user'
4670- self.assertIn(expected, self.ui.backend._called)
4671- self.assertEqual(self.ui.backend._called[expected],
4672- ((APP_NAME, EMAIL, PASSWORD, NAME, CAPTCHA_ID,
4673- CAPTCHA_SOLUTION),
4674- dict(reply_handler=gui.NO_OP,
4675- error_handler=gui.NO_OP)))
4676+ self.assert_backend_called('register_user',
4677+ APP_NAME, EMAIL, PASSWORD, NAME, CAPTCHA_ID, CAPTCHA_SOLUTION)
4678
4679 def test_join_ok_button_clicked_morphs_to_processing_page(self):
4680 """Clicking 'join_ok_button' presents the processing vbox."""
4681@@ -695,8 +723,8 @@
4682 'processing_vbox must have two children.')
4683
4684 spinner, label = box.get_children()
4685- self.assertIsInstance(spinner, gtk.Spinner)
4686- self.assertIsInstance(label, gtk.Label)
4687+ self.assertIsInstance(spinner, Gtk.Spinner)
4688+ self.assertIsInstance(label, Gtk.Label)
4689
4690 self.assertTrue(spinner.get_property('visible'),
4691 'the processing spinner should be visible.')
4692@@ -715,6 +743,8 @@
4693 def test_captcha_filename_is_different_each_time(self):
4694 """The captcha image is different each time."""
4695 ui = self.gui_class(**self.kwargs)
4696+ self.addCleanup(ui.destroy)
4697+
4698 self.assertNotEqual(self.ui._captcha_filename, ui._captcha_filename)
4699
4700 def test_captcha_image_is_removed_when_exiting(self):
4701@@ -736,8 +766,8 @@
4702 'captcha_loading must have two children.')
4703
4704 spinner, label = box.get_children()
4705- self.assertIsInstance(spinner, gtk.Spinner)
4706- self.assertIsInstance(label, gtk.Label)
4707+ self.assertIsInstance(spinner, Gtk.Spinner)
4708+ self.assertIsInstance(label, Gtk.Label)
4709
4710 self.assertTrue(spinner.get_property('visible'),
4711 'the captcha_loading spinner should be visible.')
4712@@ -771,12 +801,8 @@
4713 def test_captcha_image_is_requested_as_startup(self):
4714 """The captcha image is requested at startup."""
4715 # assert generate_captcha was called
4716- expected = 'generate_captcha'
4717- self.assertIn(expected, self.ui.backend._called)
4718- self.assertEqual(self.ui.backend._called[expected],
4719- ((APP_NAME, self.ui._captcha_filename),
4720- dict(reply_handler=gui.NO_OP,
4721- error_handler=gui.NO_OP)))
4722+ self.assert_backend_called('generate_captcha',
4723+ APP_NAME, self.ui._captcha_filename)
4724
4725 def test_captcha_is_shown_when_available(self):
4726 """The captcha image is shown when available."""
4727@@ -872,7 +898,7 @@
4728 @defer.inlineCallbacks
4729 def setUp(self):
4730 yield super(TermsAndConditionsBrowserTestCase, self).setUp()
4731- self.patch(webkit, 'WebView', FakedEmbeddedBrowser)
4732+ self.patch(WebKit, 'WebView', FakedEmbeddedBrowser)
4733
4734 self.ui.tc_button.clicked()
4735 self.addCleanup(self.ui.tc_browser_vbox.hide)
4736@@ -968,10 +994,10 @@
4737
4738 def test_navigation_requested_succeeds_for_no_clicking(self):
4739 """The navigation request succeeds when user hasn't clicked a link."""
4740- action = webkit.WebNavigationAction()
4741+ action = WebKit.WebNavigationAction()
4742 action.set_reason(gui.WEBKIT_WEB_NAVIGATION_REASON_OTHER)
4743
4744- decision = webkit.WebPolicyDecision()
4745+ decision = WebKit.WebPolicyDecision()
4746 decision.use = self._set_called
4747
4748 kwargs = dict(browser=self.browser, frame=None, request=None,
4749@@ -981,10 +1007,10 @@
4750
4751 def test_navigation_requested_ignores_clicked_links(self):
4752 """The navigation request is ignored if a link was clicked."""
4753- action = webkit.WebNavigationAction()
4754+ action = WebKit.WebNavigationAction()
4755 action.set_reason(gui.WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED)
4756
4757- decision = webkit.WebPolicyDecision()
4758+ decision = WebKit.WebPolicyDecision()
4759 decision.ignore = self._set_called
4760
4761 self.patch(gui.webbrowser, 'open', lambda *args, **kwargs: None)
4762@@ -1007,11 +1033,11 @@
4763
4764 """
4765 url = 'http://something.com/yadda'
4766- action = webkit.WebNavigationAction()
4767+ action = WebKit.WebNavigationAction()
4768 action.set_reason(gui.WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED)
4769 action.set_original_uri(url)
4770
4771- decision = webkit.WebPolicyDecision()
4772+ decision = WebKit.WebPolicyDecision()
4773 decision.ignore = gui.NO_OP
4774
4775 self.patch(gui.webbrowser, 'open', self._set_called)
4776@@ -1098,12 +1124,7 @@
4777 def test_on_verify_token_button_clicked_calls_backend(self):
4778 """Verify token button triggers call to backend."""
4779 self.click_verify_email_with_valid_data()
4780- expected = self.method
4781- self.assertIn(expected, self.ui.backend._called)
4782- self.assertEqual(self.ui.backend._called[expected],
4783- (self.method_args,
4784- dict(reply_handler=gui.NO_OP,
4785- error_handler=gui.NO_OP)))
4786+ self.assert_backend_called(self.method, *self.method_args)
4787
4788 def test_on_verify_token_button_clicked(self):
4789 """Verify token uses cached user_email and user_password."""
4790@@ -1117,10 +1138,7 @@
4791 self.ui.email_token_entry.set_text(EMAIL_TOKEN)
4792
4793 self.ui.on_verify_token_button_clicked()
4794- self.assertEqual(self.ui.backend._called[self.method],
4795- (tuple(method_args),
4796- dict(reply_handler=gui.NO_OP,
4797- error_handler=gui.NO_OP)))
4798+ self.assert_backend_called(self.method, *tuple(method_args))
4799
4800 def test_on_verify_token_button_shows_processing_page(self):
4801 """Verify token button triggers call to backend."""
4802@@ -1211,7 +1229,7 @@
4803
4804 kwargs = dict(app_name=APP_NAME, tc_url=TC_URL, help_text=HELP_TEXT,
4805 ping_url=PING_URL)
4806- method = 'validate_email_with_ping'
4807+ method = 'validate_email_and_ping'
4808 method_args = (APP_NAME, EMAIL, PASSWORD, EMAIL_TOKEN, PING_URL)
4809
4810
4811@@ -1455,13 +1473,7 @@
4812 def test_on_login_connect_button_clicked(self):
4813 """Clicking login_ok_button calls backend.login."""
4814 self.click_connect_with_valid_data()
4815-
4816- expected = self.method
4817- self.assertIn(expected, self.ui.backend._called)
4818- self.assertEqual(self.ui.backend._called[expected],
4819- (self.method_args,
4820- dict(reply_handler=gui.NO_OP,
4821- error_handler=gui.NO_OP)))
4822+ self.assert_backend_called(self.method, *self.method_args)
4823
4824 def test_on_login_connect_button_clicked_morphs_to_processing_page(self):
4825 """Clicking login_ok_button morphs to the processing page."""
4826@@ -1543,7 +1555,7 @@
4827
4828 kwargs = dict(app_name=APP_NAME, tc_url=TC_URL, help_text=HELP_TEXT,
4829 ping_url=PING_URL)
4830- method = 'login_with_ping'
4831+ method = 'login_and_ping'
4832 method_args = (APP_NAME, EMAIL, PASSWORD, PING_URL)
4833
4834
4835@@ -1665,12 +1677,8 @@
4836 def test_on_request_password_token_ok_button_clicked_calls_backend(self):
4837 """Clicking request_password_token_ok_button the backend is called."""
4838 self.click_request_password_token_with_valid_data()
4839- expected = 'request_password_reset_token'
4840- self.assertIn(expected, self.ui.backend._called)
4841- self.assertEqual(self.ui.backend._called[expected],
4842- ((APP_NAME, EMAIL),
4843- dict(reply_handler=gui.NO_OP,
4844- error_handler=gui.NO_OP)))
4845+ self.assert_backend_called('request_password_reset_token',
4846+ APP_NAME, EMAIL)
4847
4848 def test_on_password_reset_token_sent_morphs_window(self):
4849 """When the reset token was sent, the reset password page is shown."""
4850@@ -1805,12 +1813,8 @@
4851 def test_on_set_new_password_ok_button_clicked_calls_backend(self):
4852 """Clicking set_new_password_ok_button the backend is called."""
4853 self.click_set_new_password_with_valid_data()
4854- expected = 'set_new_password'
4855- self.assertIn(expected, self.ui.backend._called)
4856- self.assertEqual(self.ui.backend._called[expected],
4857- ((APP_NAME, EMAIL, RESET_PASSWORD_TOKEN, PASSWORD),
4858- dict(reply_handler=gui.NO_OP,
4859- error_handler=gui.NO_OP)))
4860+ self.assert_backend_called('set_new_password',
4861+ APP_NAME, EMAIL, RESET_PASSWORD_TOKEN, PASSWORD)
4862
4863 def test_on_password_changed_shows_login_page(self):
4864 """When password was successfuly changed the login page is shown."""
4865@@ -2070,10 +2074,6 @@
4866 class ReturnCodeTestCase(UbuntuSSOClientTestCase):
4867 """Test the return codes."""
4868
4869- LOGIN_SUCCESS = gui.LOGIN_SUCCESS
4870- REGISTRATION_SUCCESS = gui.REGISTRATION_SUCCESS
4871- USER_CANCELLATION = gui.USER_CANCELLATION
4872-
4873 @defer.inlineCallbacks
4874 def setUp(self):
4875 yield super(ReturnCodeTestCase, self).setUp()
4876@@ -2081,7 +2081,7 @@
4877
4878 def test_closing_main_window(self):
4879 """When closing the main window, USER_CANCELLATION is called."""
4880- self.ui.window.emit('delete-event', gtk.gdk.Event(gtk.gdk.DELETE))
4881+ self.ui.window.emit('delete-event', Gdk.Event())
4882 self.assertEqual(self._called, ((gui.USER_CANCELLATION,), {}))
4883
4884 def test_every_cancel_calls_proper_callback(self):
4885@@ -2108,7 +2108,7 @@
4886 self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL)
4887 self.ui.on_close_clicked()
4888
4889- self.assertEqual(self._called, ((gui.REGISTRATION_SUCCESS,), {}))
4890+ self.assertEqual(self._called, ((gui.USER_SUCCESS,), {}))
4891
4892 def test_on_email_validation_error_proper_callback_is_called(self):
4893 """On EmailValidationError, USER_CANCELLATION is called."""
4894@@ -2122,7 +2122,7 @@
4895 self.ui.on_logged_in(app_name=APP_NAME, email=EMAIL)
4896 self.ui.on_close_clicked()
4897
4898- self.assertEqual(self._called, ((gui.LOGIN_SUCCESS,), {}))
4899+ self.assertEqual(self._called, ((gui.USER_SUCCESS,), {}))
4900
4901 def test_on_login_error_proper_callback_is_called(self):
4902 """On LoginError, USER_CANCELLATION is called."""
4903@@ -2145,7 +2145,7 @@
4904 self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL)
4905 self.ui.on_close_clicked()
4906
4907- self.assertEqual(self._called, ((gui.REGISTRATION_SUCCESS,), {}))
4908+ self.assertEqual(self._called, ((gui.USER_SUCCESS,), {}))
4909
4910 def test_login_success_even_if_prior_login_error(self):
4911 """Only one callback is called with the final outcome.
4912@@ -2160,7 +2160,7 @@
4913 self.ui.on_logged_in(app_name=APP_NAME, email=EMAIL)
4914 self.ui.on_close_clicked()
4915
4916- self.assertEqual(self._called, ((gui.LOGIN_SUCCESS,), {}))
4917+ self.assertEqual(self._called, ((gui.USER_SUCCESS,), {}))
4918
4919 def test_user_cancelation_even_if_prior_registration_error(self):
4920 """Only one callback is called with the final outcome.
4921
4922=== added file 'ubuntu_sso/gtk/tests/test_main.py'
4923--- ubuntu_sso/gtk/tests/test_main.py 1970-01-01 00:00:00 +0000
4924+++ ubuntu_sso/gtk/tests/test_main.py 2012-02-14 22:04:20 +0000
4925@@ -0,0 +1,39 @@
4926+# -*- coding: utf-8 -*-
4927+#
4928+# Copyright 2012 Canonical Ltd.
4929+#
4930+# This program is free software: you can redistribute it and/or modify it
4931+# under the terms of the GNU General Public License version 3, as published
4932+# by the Free Software Foundation.
4933+#
4934+# This program is distributed in the hope that it will be useful, but
4935+# WITHOUT ANY WARRANTY; without even the implied warranties of
4936+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
4937+# PURPOSE. See the GNU General Public License for more details.
4938+#
4939+# You should have received a copy of the GNU General Public License along
4940+# with this program. If not, see <http://www.gnu.org/licenses/>.
4941+
4942+"""Tests for the main module."""
4943+
4944+from twisted.trial.unittest import TestCase
4945+
4946+from ubuntu_sso.gtk import main
4947+
4948+
4949+class BasicTestCase(TestCase):
4950+ """Test case with a helper tracker."""
4951+
4952+ def test_main(self):
4953+ """Calling main.main() a UI instance is created."""
4954+ called = []
4955+ self.patch(main, 'UbuntuSSOClientGUI',
4956+ lambda **kw: called.append(('GUI', kw)))
4957+ self.patch(main.Gtk, 'main',
4958+ lambda: called.append('main'))
4959+
4960+ kwargs = dict(foo='foo', bar='bar', baz='yadda', yadda=0)
4961+ main.main(**kwargs)
4962+
4963+ kwargs['close_callback'] = main.Gtk.main_quit
4964+ self.assertEqual(called, [('GUI', kwargs), 'main'])
4965
4966=== modified file 'ubuntu_sso/keyring/__init__.py'
4967--- ubuntu_sso/keyring/__init__.py 2011-10-17 18:24:55 +0000
4968+++ ubuntu_sso/keyring/__init__.py 2012-02-14 22:04:20 +0000
4969@@ -29,8 +29,8 @@
4970
4971 logger = setup_logging("ubuntu_sso.keyring")
4972
4973-TOKEN_SEPARATOR = ' @ '
4974-SEPARATOR_REPLACEMENT = ' AT '
4975+TOKEN_SEPARATOR = u' @ '
4976+SEPARATOR_REPLACEMENT = u' AT '
4977
4978 U1_APP_NAME = "Ubuntu One"
4979 U1_KEY_NAME = "UbuntuOne token for https://ubuntuone.com"
4980@@ -41,26 +41,34 @@
4981
4982
4983 def gethostname():
4984- """Get the hostname, encoded in utf-8."""
4985+ """Get the hostname, return the name as unicode."""
4986 sys_encoding = sys.getfilesystemencoding()
4987 hostname = socket.gethostname().decode(sys_encoding)
4988- return hostname.encode("utf-8")
4989+ return hostname
4990
4991
4992 def get_old_token_name(app_name):
4993- """Build the token name (old style)."""
4994+ """Build the token name (old style). Return an unicode."""
4995 quoted_app_name = urllib.quote(app_name)
4996 computer_name = gethostname()
4997 quoted_computer_name = urllib.quote(computer_name)
4998- return "%s - %s" % (quoted_app_name, quoted_computer_name)
4999+
5000+ assert isinstance(computer_name, unicode)
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches