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
=== modified file '.bzrignore'
--- .bzrignore 2011-04-11 09:38:16 +0000
+++ .bzrignore 2012-02-14 22:04:20 +0000
@@ -1,16 +1,9 @@
1_trial_temp1_trial_temp
2data/*.service2data/*.service
3MANIFEST
3build/4build/
4dist/5dist/
5MANIFEST
6po/ubuntu-sso-client.pot6po/ubuntu-sso-client.pot
7ubuntu_sso/qt/captcha_ui.py7ubuntu_sso/constants.py
8ubuntu_sso/qt/choose_sign_in_ui.py8ubuntu_sso/qt/ui/*_ui.py
9ubuntu_sso/qt/current_user_sign_in_ui.py9ubuntu_sso/qt/ui/*_rc.py
10ubuntu_sso/qt/email_verification_ui.py
11ubuntu_sso/qt/setup_account_ui.py
12ubuntu_sso/qt/terms_and_conditions_ui.py
13ubuntu_sso/qt/success_message_ui.py
14ubuntu_sso/qt/error_message_ui.py
15ubuntu_sso/qt/forgotten_password_ui.py
16ubuntu_sso/qt/reset_password_ui.py
1710
=== modified file 'bin/ubuntu-sso-login-gtk'
--- bin/ubuntu-sso-login-gtk 2012-01-16 21:10:12 +0000
+++ bin/ubuntu-sso-login-gtk 2012-02-14 22:04:20 +0000
@@ -20,7 +20,8 @@
20# Invalid name "ubuntu-sso-login-gtk", pylint: disable=C010320# Invalid name "ubuntu-sso-login-gtk", pylint: disable=C0103
21# Access to a protected member, pylint: disable=W021221# Access to a protected member, pylint: disable=W0212
2222
23from ubuntu_sso.gtk.main import parse_args, main23from ubuntu_sso.gtk.main import main
24from ubuntu_sso.utils.ui import parse_args
2425
25from dbus.mainloop.glib import DBusGMainLoop26from dbus.mainloop.glib import DBusGMainLoop
26DBusGMainLoop(set_as_default=True)27DBusGMainLoop(set_as_default=True)
2728
=== added file 'bin/ubuntu-sso-login-qt'
--- bin/ubuntu-sso-login-qt 1970-01-01 00:00:00 +0000
+++ bin/ubuntu-sso-login-qt 2012-02-14 22:04:20 +0000
@@ -0,0 +1,32 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# Copyright 2012 Canonical Ltd.
5#
6# This program is free software: you can redistribute it and/or modify it
7# under the terms of the GNU General Public License version 3, as published
8# by the Free Software Foundation.
9#
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranties of
12# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13# PURPOSE. See the GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License along
16# with this program. If not, see <http://www.gnu.org/licenses/>.
17
18"""Start the sso GTK UI."""
19
20# Invalid name "ubuntu-sso-login-qt", pylint: disable=C0103
21# Access to a protected member, pylint: disable=W0212
22
23from ubuntu_sso.qt.main import main
24from ubuntu_sso.utils.ui import parse_args
25
26from dbus.mainloop.qt import DBusQtMainLoop
27DBusQtMainLoop(set_as_default=True)
28
29
30if __name__ == "__main__":
31 args = parse_args()
32 main(**dict(args._get_kwargs()))
033
=== added file 'bin/ubuntu-sso-proxy-creds-qt'
--- bin/ubuntu-sso-proxy-creds-qt 1970-01-01 00:00:00 +0000
+++ bin/ubuntu-sso-proxy-creds-qt 2012-02-14 22:04:20 +0000
@@ -0,0 +1,33 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# Copyright 2012 Canonical Ltd.
5#
6# This program is free software: you can redistribute it and/or modify it
7# under the terms of the GNU General Public License version 3, as published
8# by the Free Software Foundation.
9#
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranties of
12# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13# PURPOSE. See the GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License along
16# with this program. If not, see <http://www.gnu.org/licenses/>.
17
18"""Start the QT proxy creds dialog."""
19
20# Invalid name, pylint: disable=C0103
21
22import os
23# HACK: At the moment we need to do that until sso is refactored
24os.environ['USE_QT_MAINLOOP'] = '1'
25
26# set the dbus main loop to be used
27from dbus.mainloop.qt import DBusQtMainLoop
28DBusQtMainLoop(set_as_default=True)
29
30from ubuntu_sso.qt.proxy_dialog import main
31
32if __name__ == "__main__":
33 main()
034
=== modified file 'data/gtk/ui.glade'
--- data/gtk/ui.glade 2011-09-19 13:09:46 +0000
+++ data/gtk/ui.glade 2012-02-14 22:04:20 +0000
@@ -1,72 +1,14 @@
1<?xml version="1.0" encoding="UTF-8"?>1<?xml version="1.0" encoding="UTF-8"?>
2<interface>2<interface>
3 <requires lib="gtk+" version="2.16"/>3 <requires lib="gtk+" version="2.16"/>
4 <!-- interface-naming-policy project-wide -->
5 <object class="GtkWindow" id="window">
6 <property name="border_width">10</property>
7 <property name="window_position">center</property>
8 <signal name="delete_event" handler="on_close_clicked"/>
9 <child>
10 <object class="GtkVBox" id="window_vbox">
11 <property name="visible">True</property>
12 <property name="spacing">5</property>
13 <child>
14 <object class="GtkLabel" id="header_label">
15 <property name="visible">True</property>
16 <property name="xalign">0</property>
17 <property name="label" translatable="yes">Header Label </property>
18 <property name="wrap">True</property>
19 </object>
20 <packing>
21 <property name="expand">False</property>
22 <property name="padding">5</property>
23 <property name="position">0</property>
24 </packing>
25 </child>
26 <child>
27 <object class="GtkLabel" id="help_label">
28 <property name="visible">True</property>
29 <property name="xalign">0</property>
30 <property name="label" translatable="yes">help label</property>
31 <property name="wrap">True</property>
32 </object>
33 <packing>
34 <property name="expand">False</property>
35 <property name="position">1</property>
36 </packing>
37 </child>
38 <child>
39 <object class="GtkLabel" id="warning_label">
40 <property name="visible">True</property>
41 <property name="xalign">0</property>
42 <property name="label" translatable="yes">warning label</property>
43 <property name="wrap">True</property>
44 </object>
45 <packing>
46 <property name="expand">False</property>
47 <property name="position">2</property>
48 </packing>
49 </child>
50 <child>
51 <object class="GtkNotebook" id="content">
52 <property name="visible">True</property>
53 <property name="can_focus">True</property>
54 <property name="show_tabs">False</property>
55 <property name="show_border">False</property>
56 </object>
57 <packing>
58 <property name="position">3</property>
59 </packing>
60 </child>
61 </object>
62 </child>
63 </object>
64 <object class="GtkVBox" id="enter_details_vbox">4 <object class="GtkVBox" id="enter_details_vbox">
65 <property name="visible">True</property>5 <property name="visible">True</property>
6 <property name="can_focus">False</property>
66 <property name="spacing">5</property>7 <property name="spacing">5</property>
67 <child>8 <child>
68 <object class="GtkHBox" id="emails_hbox">9 <object class="GtkHBox" id="emails_hbox">
69 <property name="visible">True</property>10 <property name="visible">True</property>
11 <property name="can_focus">False</property>
70 <property name="spacing">5</property>12 <property name="spacing">5</property>
71 <property name="homogeneous">True</property>13 <property name="homogeneous">True</property>
72 <child>14 <child>
@@ -78,12 +20,14 @@
78 </object>20 </object>
79 <packing>21 <packing>
80 <property name="expand">False</property>22 <property name="expand">False</property>
23 <property name="fill">True</property>
81 <property name="position">0</property>24 <property name="position">0</property>
82 </packing>25 </packing>
83 </child>26 </child>
84 <child>27 <child>
85 <object class="GtkHBox" id="passwords_hbox">28 <object class="GtkHBox" id="passwords_hbox">
86 <property name="visible">True</property>29 <property name="visible">True</property>
30 <property name="can_focus">False</property>
87 <property name="spacing">5</property>31 <property name="spacing">5</property>
88 <property name="homogeneous">True</property>32 <property name="homogeneous">True</property>
89 <child>33 <child>
@@ -95,38 +39,45 @@
95 </object>39 </object>
96 <packing>40 <packing>
97 <property name="expand">False</property>41 <property name="expand">False</property>
42 <property name="fill">True</property>
98 <property name="position">1</property>43 <property name="position">1</property>
99 </packing>44 </packing>
100 </child>45 </child>
101 <child>46 <child>
102 <object class="GtkLabel" id="password_help_label">47 <object class="GtkLabel" id="password_help_label">
103 <property name="visible">True</property>48 <property name="visible">True</property>
49 <property name="can_focus">False</property>
104 <property name="label">password help</property>50 <property name="label">password help</property>
105 <property name="wrap">True</property>51 <property name="wrap">True</property>
106 </object>52 </object>
107 <packing>53 <packing>
108 <property name="expand">False</property>54 <property name="expand">False</property>
55 <property name="fill">True</property>
109 <property name="position">2</property>56 <property name="position">2</property>
110 </packing>57 </packing>
111 </child>58 </child>
112 <child>59 <child>
113 <object class="GtkAlignment" id="alignment5">60 <object class="GtkAlignment" id="alignment5">
114 <property name="visible">True</property>61 <property name="visible">True</property>
62 <property name="can_focus">False</property>
115 <property name="xscale">0</property>63 <property name="xscale">0</property>
116 <property name="yscale">0</property>64 <property name="yscale">0</property>
117 <child>65 <child>
118 <object class="GtkHBox" id="hbox1">66 <object class="GtkHBox" id="hbox1">
119 <property name="visible">True</property>67 <property name="visible">True</property>
68 <property name="can_focus">False</property>
120 <child>69 <child>
121 <object class="GtkVBox" id="captcha_vbox">70 <object class="GtkVBox" id="captcha_vbox">
122 <property name="width_request">300</property>71 <property name="width_request">300</property>
123 <property name="height_request">60</property>72 <property name="height_request">60</property>
124 <property name="visible">True</property>73 <property name="visible">True</property>
74 <property name="can_focus">False</property>
125 <child>75 <child>
126 <object class="GtkEventBox" id="captcha_loading">76 <object class="GtkEventBox" id="captcha_loading">
127 <property name="width_request">300</property>77 <property name="width_request">300</property>
128 <property name="height_request">60</property>78 <property name="height_request">60</property>
129 <property name="visible">True</property>79 <property name="visible">True</property>
80 <property name="can_focus">False</property>
130 <child>81 <child>
131 <placeholder/>82 <placeholder/>
132 </child>83 </child>
@@ -141,9 +92,12 @@
141 <object class="GtkImage" id="captcha_image">92 <object class="GtkImage" id="captcha_image">
142 <property name="width_request">300</property>93 <property name="width_request">300</property>
143 <property name="visible">True</property>94 <property name="visible">True</property>
95 <property name="can_focus">False</property>
144 <property name="stock">gtk-missing-image</property>96 <property name="stock">gtk-missing-image</property>
145 </object>97 </object>
146 <packing>98 <packing>
99 <property name="expand">True</property>
100 <property name="fill">True</property>
147 <property name="position">1</property>101 <property name="position">1</property>
148 </packing>102 </packing>
149 </child>103 </child>
@@ -157,23 +111,28 @@
157 <child>111 <child>
158 <object class="GtkVBox" id="vbox1">112 <object class="GtkVBox" id="vbox1">
159 <property name="visible">True</property>113 <property name="visible">True</property>
114 <property name="can_focus">False</property>
160 <child>115 <child>
161 <object class="GtkButton" id="captcha_reload_button">116 <object class="GtkButton" id="captcha_reload_button">
117 <property name="use_action_appearance">False</property>
162 <property name="visible">True</property>118 <property name="visible">True</property>
163 <property name="can_focus">True</property>119 <property name="can_focus">True</property>
164 <property name="receives_default">True</property>120 <property name="receives_default">True</property>
121 <property name="use_action_appearance">False</property>
165 <property name="relief">none</property>122 <property name="relief">none</property>
166 <property name="focus_on_click">False</property>123 <property name="focus_on_click">False</property>
167 <signal name="clicked" handler="on_captcha_reload_button_clicked"/>124 <signal name="clicked" handler="on_captcha_reload_button_clicked" swapped="no"/>
168 <child>125 <child>
169 <object class="GtkImage" id="image1">126 <object class="GtkImage" id="image1">
170 <property name="visible">True</property>127 <property name="visible">True</property>
128 <property name="can_focus">False</property>
171 <property name="icon_name">reload</property>129 <property name="icon_name">reload</property>
172 </object>130 </object>
173 </child>131 </child>
174 </object>132 </object>
175 <packing>133 <packing>
176 <property name="expand">False</property>134 <property name="expand">False</property>
135 <property name="fill">True</property>
177 <property name="position">0</property>136 <property name="position">0</property>
178 </packing>137 </packing>
179 </child>138 </child>
@@ -186,6 +145,7 @@
186 </object>145 </object>
187 <packing>146 <packing>
188 <property name="expand">False</property>147 <property name="expand">False</property>
148 <property name="fill">True</property>
189 <property name="position">1</property>149 <property name="position">1</property>
190 </packing>150 </packing>
191 </child>151 </child>
@@ -194,64 +154,76 @@
194 </object>154 </object>
195 <packing>155 <packing>
196 <property name="expand">False</property>156 <property name="expand">False</property>
157 <property name="fill">True</property>
197 <property name="position">3</property>158 <property name="position">3</property>
198 </packing>159 </packing>
199 </child>160 </child>
200 <child>161 <child>
201 <object class="GtkVBox" id="captcha_solution_vbox">162 <object class="GtkVBox" id="captcha_solution_vbox">
202 <property name="visible">True</property>163 <property name="visible">True</property>
164 <property name="can_focus">False</property>
203 <child>165 <child>
204 <placeholder/>166 <placeholder/>
205 </child>167 </child>
206 </object>168 </object>
207 <packing>169 <packing>
208 <property name="expand">False</property>170 <property name="expand">False</property>
171 <property name="fill">True</property>
209 <property name="position">4</property>172 <property name="position">4</property>
210 </packing>173 </packing>
211 </child>174 </child>
212 <child>175 <child>
213 <object class="GtkCheckButton" id="yes_to_updates_checkbutton">176 <object class="GtkCheckButton" id="yes_to_updates_checkbutton">
214 <property name="label" translatable="yes">yes to updates</property>177 <property name="label" translatable="yes">yes to updates</property>
178 <property name="use_action_appearance">False</property>
215 <property name="visible">True</property>179 <property name="visible">True</property>
216 <property name="can_focus">True</property>180 <property name="can_focus">True</property>
217 <property name="receives_default">False</property>181 <property name="receives_default">False</property>
182 <property name="use_action_appearance">False</property>
218 <property name="active">True</property>183 <property name="active">True</property>
219 <property name="draw_indicator">True</property>184 <property name="draw_indicator">True</property>
220 </object>185 </object>
221 <packing>186 <packing>
222 <property name="expand">False</property>187 <property name="expand">False</property>
188 <property name="fill">True</property>
223 <property name="position">5</property>189 <property name="position">5</property>
224 </packing>190 </packing>
225 </child>191 </child>
226 <child>192 <child>
227 <object class="GtkVBox" id="tc_vbox">193 <object class="GtkVBox" id="tc_vbox">
228 <property name="visible">True</property>194 <property name="visible">True</property>
195 <property name="can_focus">False</property>
229 <property name="spacing">5</property>196 <property name="spacing">5</property>
230 <child>197 <child>
231 <object class="GtkCheckButton" id="yes_to_tc_checkbutton">198 <object class="GtkCheckButton" id="yes_to_tc_checkbutton">
232 <property name="label" translatable="yes">yes to tc</property>199 <property name="label" translatable="yes">yes to tc</property>
200 <property name="use_action_appearance">False</property>
233 <property name="visible">True</property>201 <property name="visible">True</property>
234 <property name="can_focus">True</property>202 <property name="can_focus">True</property>
235 <property name="receives_default">False</property>203 <property name="receives_default">False</property>
236 <property name="active">False</property>204 <property name="use_action_appearance">False</property>
237 <property name="draw_indicator">True</property>205 <property name="draw_indicator">True</property>
238 </object>206 </object>
239 <packing>207 <packing>
240 <property name="expand">False</property>208 <property name="expand">False</property>
209 <property name="fill">True</property>
241 <property name="position">0</property>210 <property name="position">0</property>
242 </packing>211 </packing>
243 </child>212 </child>
244 <child>213 <child>
245 <object class="GtkHButtonBox" id="hbuttonbox3">214 <object class="GtkHButtonBox" id="hbuttonbox3">
246 <property name="visible">True</property>215 <property name="visible">True</property>
216 <property name="can_focus">False</property>
247 <property name="layout_style">start</property>217 <property name="layout_style">start</property>
248 <child>218 <child>
249 <object class="GtkButton" id="tc_button">219 <object class="GtkButton" id="tc_button">
250 <property name="label">show tc</property>220 <property name="label">show tc</property>
221 <property name="use_action_appearance">False</property>
251 <property name="visible">True</property>222 <property name="visible">True</property>
252 <property name="can_focus">True</property>223 <property name="can_focus">True</property>
253 <property name="receives_default">True</property>224 <property name="receives_default">True</property>
254 <signal name="clicked" handler="on_tc_button_clicked"/>225 <property name="use_action_appearance">False</property>
226 <signal name="clicked" handler="on_tc_button_clicked" swapped="no"/>
255 </object>227 </object>
256 <packing>228 <packing>
257 <property name="expand">False</property>229 <property name="expand">False</property>
@@ -262,42 +234,53 @@
262 </object>234 </object>
263 <packing>235 <packing>
264 <property name="expand">False</property>236 <property name="expand">False</property>
237 <property name="fill">True</property>
265 <property name="position">1</property>238 <property name="position">1</property>
266 </packing>239 </packing>
267 </child>240 </child>
268 <child>241 <child>
269 <object class="GtkLabel" id="tc_warning_label">242 <object class="GtkLabel" id="tc_warning_label">
270 <property name="visible">True</property>243 <property name="visible">True</property>
244 <property name="can_focus">False</property>
271 <property name="xalign">0</property>245 <property name="xalign">0</property>
272 <property name="label">tc warning</property>246 <property name="label">tc warning</property>
273 <property name="wrap">True</property>247 <property name="wrap">True</property>
274 </object>248 </object>
275 <packing>249 <packing>
250 <property name="expand">True</property>
251 <property name="fill">True</property>
276 <property name="position">2</property>252 <property name="position">2</property>
277 </packing>253 </packing>
278 </child>254 </child>
279 </object>255 </object>
280 <packing>256 <packing>
281 <property name="expand">False</property>257 <property name="expand">False</property>
258 <property name="fill">True</property>
282 <property name="position">6</property>259 <property name="position">6</property>
283 </packing>260 </packing>
284 </child>261 </child>
285 <child>262 <child>
286 <object class="GtkHBox" id="hbox2">263 <object class="GtkHBox" id="hbox2">
287 <property name="visible">True</property>264 <property name="visible">True</property>
265 <property name="can_focus">False</property>
288 <property name="spacing">5</property>266 <property name="spacing">5</property>
289 <child>267 <child>
290 <object class="GtkHButtonBox" id="hbuttonbox9">268 <object class="GtkHButtonBox" id="hbuttonbox9">
291 <property name="visible">True</property>269 <property name="visible">True</property>
270 <property name="can_focus">False</property>
292 <property name="layout_style">start</property>271 <property name="layout_style">start</property>
293 <child>272 <child>
294 <object class="GtkLinkButton" id="login_button">273 <object class="GtkLinkButton" id="login_button">
295 <property name="label">login button</property>274 <property name="label">login button</property>
275 <property name="use_action_appearance">False</property>
296 <property name="visible">True</property>276 <property name="visible">True</property>
297 <property name="can_focus">True</property>277 <property name="can_focus">True</property>
298 <property name="receives_default">True</property>278 <property name="receives_default">True</property>
279 <property name="use_action_appearance">False</property>
299 <property name="relief">none</property>280 <property name="relief">none</property>
300 <signal name="clicked" handler="on_sign_in_button_clicked"/>281 <property name="uri">foo</property>
282 <signal name="activate-link" handler="on_activate_link" swapped="no"/>
283 <signal name="clicked" handler="on_sign_in_button_clicked" swapped="no"/>
301 </object>284 </object>
302 <packing>285 <packing>
303 <property name="expand">False</property>286 <property name="expand">False</property>
@@ -308,20 +291,24 @@
308 </object>291 </object>
309 <packing>292 <packing>
310 <property name="expand">False</property>293 <property name="expand">False</property>
294 <property name="fill">True</property>
311 <property name="position">0</property>295 <property name="position">0</property>
312 </packing>296 </packing>
313 </child>297 </child>
314 <child>298 <child>
315 <object class="GtkHButtonBox" id="hbuttonbox1">299 <object class="GtkHButtonBox" id="hbuttonbox1">
316 <property name="visible">True</property>300 <property name="visible">True</property>
301 <property name="can_focus">False</property>
317 <property name="spacing">5</property>302 <property name="spacing">5</property>
318 <property name="layout_style">end</property>303 <property name="layout_style">end</property>
319 <child>304 <child>
320 <object class="GtkButton" id="join_cancel_button">305 <object class="GtkButton" id="join_cancel_button">
321 <property name="label">gtk-cancel</property>306 <property name="label">gtk-cancel</property>
307 <property name="use_action_appearance">False</property>
322 <property name="visible">True</property>308 <property name="visible">True</property>
323 <property name="can_focus">True</property>309 <property name="can_focus">True</property>
324 <property name="receives_default">True</property>310 <property name="receives_default">True</property>
311 <property name="use_action_appearance">False</property>
325 <property name="use_stock">True</property>312 <property name="use_stock">True</property>
326 </object>313 </object>
327 <packing>314 <packing>
@@ -333,11 +320,13 @@
333 <child>320 <child>
334 <object class="GtkButton" id="join_ok_button">321 <object class="GtkButton" id="join_ok_button">
335 <property name="label">gtk-go-forward</property>322 <property name="label">gtk-go-forward</property>
323 <property name="use_action_appearance">False</property>
336 <property name="visible">True</property>324 <property name="visible">True</property>
337 <property name="can_focus">True</property>325 <property name="can_focus">True</property>
338 <property name="receives_default">True</property>326 <property name="receives_default">True</property>
327 <property name="use_action_appearance">False</property>
339 <property name="use_stock">True</property>328 <property name="use_stock">True</property>
340 <signal name="clicked" handler="on_join_ok_button_clicked"/>329 <signal name="clicked" handler="on_join_ok_button_clicked" swapped="no"/>
341 </object>330 </object>
342 <packing>331 <packing>
343 <property name="expand">False</property>332 <property name="expand">False</property>
@@ -348,6 +337,7 @@
348 </object>337 </object>
349 <packing>338 <packing>
350 <property name="expand">False</property>339 <property name="expand">False</property>
340 <property name="fill">True</property>
351 <property name="pack_type">end</property>341 <property name="pack_type">end</property>
352 <property name="position">1</property>342 <property name="position">1</property>
353 </packing>343 </packing>
@@ -355,122 +345,72 @@
355 </object>345 </object>
356 <packing>346 <packing>
357 <property name="expand">False</property>347 <property name="expand">False</property>
348 <property name="fill">True</property>
358 <property name="pack_type">end</property>349 <property name="pack_type">end</property>
359 <property name="position">7</property>350 <property name="position">7</property>
360 </packing>351 </packing>
361 </child>352 </child>
362 </object>353 </object>
363 <object class="GtkVBox" id="processing_vbox">354 <object class="GtkVBox" id="finish_vbox">
364 <property name="visible">True</property>355 <property name="visible">True</property>
365 <property name="spacing">10</property>356 <property name="can_focus">False</property>
366 <child>357 <property name="spacing">10</property>
367 <placeholder/>358 <child>
368 </child>359 <object class="GtkLabel" id="finish_label">
369 </object>360 <property name="visible">True</property>
370 <object class="GtkVBox" id="verify_email_vbox">361 <property name="can_focus">False</property>
371 <property name="visible">True</property>362 <property name="wrap">True</property>
372 <property name="spacing">10</property>363 </object>
373 <child>364 <packing>
374 <object class="GtkAlignment" id="alignment4">365 <property name="expand">True</property>
375 <property name="visible">True</property>366 <property name="fill">True</property>
376 <property name="xscale">0</property>367 <property name="position">0</property>
377 <property name="yscale">0</property>368 </packing>
378 <child>369 </child>
379 <object class="GtkVBox" id="verify_email_details_vbox">370 <child>
380 <property name="visible">True</property>371 <object class="GtkHButtonBox" id="hbuttonbox8">
381 <child>372 <property name="visible">True</property>
382 <placeholder/>373 <property name="can_focus">False</property>
383 </child>374 <property name="layout_style">end</property>
384 </object>375 <child>
385 </child>376 <object class="GtkButton" id="finish_close_button">
386 </object>377 <property name="label">gtk-close</property>
387 <packing>378 <property name="use_action_appearance">False</property>
388 <property name="position">0</property>379 <property name="visible">True</property>
389 </packing>380 <property name="can_focus">True</property>
390 </child>381 <property name="receives_default">True</property>
391 <child>382 <property name="use_action_appearance">False</property>
392 <object class="GtkHButtonBox" id="hbuttonbox2">383 <property name="use_stock">True</property>
393 <property name="visible">True</property>384 <signal name="clicked" handler="on_close_clicked" swapped="no"/>
394 <property name="spacing">5</property>385 </object>
395 <property name="layout_style">end</property>386 <packing>
396 <child>387 <property name="expand">False</property>
397 <object class="GtkButton" id="verify_token_button">388 <property name="fill">False</property>
398 <property name="label">gtk-ok</property>389 <property name="position">0</property>
399 <property name="visible">True</property>390 </packing>
400 <property name="can_focus">True</property>391 </child>
401 <property name="receives_default">True</property>392 </object>
402 <property name="use_stock">True</property>393 <packing>
403 <signal name="clicked" handler="on_verify_token_button_clicked"/>394 <property name="expand">False</property>
404 </object>395 <property name="fill">True</property>
405 <packing>
406 <property name="expand">False</property>
407 <property name="fill">False</property>
408 <property name="position">0</property>
409 </packing>
410 </child>
411 </object>
412 <packing>
413 <property name="expand">False</property>
414 <property name="position">1</property>
415 </packing>
416 </child>
417 </object>
418 <object class="GtkVBox" id="tc_browser_vbox">
419 <property name="visible">True</property>
420 <signal name="hide" handler="on_tc_browser_vbox_hide"/>
421 <child>
422 <object class="GtkScrolledWindow" id="tc_browser_window">
423 <property name="visible">True</property>
424 <property name="can_focus">True</property>
425 <property name="border_width">10</property>
426 <property name="hscrollbar_policy">never</property>
427 <property name="vscrollbar_policy">automatic</property>
428 <property name="shadow_type">in</property>
429 <child>
430 <placeholder/>
431 </child>
432 </object>
433 <packing>
434 <property name="position">0</property>
435 </packing>
436 </child>
437 <child>
438 <object class="GtkHButtonBox" id="hbuttonbox4">
439 <property name="visible">True</property>
440 <property name="layout_style">end</property>
441 <child>
442 <object class="GtkButton" id="tc_back_button">
443 <property name="label">gtk-go-back</property>
444 <property name="visible">True</property>
445 <property name="can_focus">True</property>
446 <property name="receives_default">True</property>
447 <property name="use_stock">True</property>
448 <signal name="clicked" handler="on_tc_back_button_clicked"/>
449 </object>
450 <packing>
451 <property name="expand">False</property>
452 <property name="fill">False</property>
453 <property name="position">0</property>
454 </packing>
455 </child>
456 </object>
457 <packing>
458 <property name="expand">False</property>
459 <property name="position">1</property>396 <property name="position">1</property>
460 </packing>397 </packing>
461 </child>398 </child>
462 </object>399 </object>
463 <object class="GtkVBox" id="login_vbox">400 <object class="GtkVBox" id="login_vbox">
464 <property name="visible">True</property>401 <property name="visible">True</property>
402 <property name="can_focus">False</property>
465 <property name="spacing">10</property>403 <property name="spacing">10</property>
466 <child>404 <child>
467 <object class="GtkAlignment" id="alignment3">405 <object class="GtkAlignment" id="alignment3">
468 <property name="visible">True</property>406 <property name="visible">True</property>
407 <property name="can_focus">False</property>
469 <property name="xscale">0</property>408 <property name="xscale">0</property>
470 <property name="yscale">0</property>409 <property name="yscale">0</property>
471 <child>410 <child>
472 <object class="GtkVBox" id="login_details_vbox">411 <object class="GtkVBox" id="login_details_vbox">
473 <property name="visible">True</property>412 <property name="visible">True</property>
413 <property name="can_focus">False</property>
474 <property name="spacing">5</property>414 <property name="spacing">5</property>
475 <child>415 <child>
476 <placeholder/>416 <placeholder/>
@@ -482,26 +422,34 @@
482 </child>422 </child>
483 </object>423 </object>
484 <packing>424 <packing>
425 <property name="expand">True</property>
426 <property name="fill">True</property>
485 <property name="position">0</property>427 <property name="position">0</property>
486 </packing>428 </packing>
487 </child>429 </child>
488 <child>430 <child>
489 <object class="GtkHBox" id="hbox3">431 <object class="GtkHBox" id="hbox3">
490 <property name="visible">True</property>432 <property name="visible">True</property>
433 <property name="can_focus">False</property>
491 <property name="spacing">5</property>434 <property name="spacing">5</property>
492 <child>435 <child>
493 <object class="GtkHButtonBox" id="hbuttonbox10">436 <object class="GtkHButtonBox" id="hbuttonbox10">
494 <property name="visible">True</property>437 <property name="visible">True</property>
438 <property name="can_focus">False</property>
495 <property name="layout_style">start</property>439 <property name="layout_style">start</property>
496 <child>440 <child>
497 <object class="GtkLinkButton" id="forgotten_password_button">441 <object class="GtkLinkButton" id="forgotten_password_button">
498 <property name="label" translatable="yes">button</property>442 <property name="label" translatable="yes">forgot password button</property>
443 <property name="use_action_appearance">False</property>
499 <property name="visible">True</property>444 <property name="visible">True</property>
500 <property name="can_focus">True</property>445 <property name="can_focus">True</property>
501 <property name="receives_default">True</property>446 <property name="receives_default">True</property>
502 <property name="has_tooltip">True</property>447 <property name="has_tooltip">True</property>
448 <property name="use_action_appearance">False</property>
503 <property name="relief">none</property>449 <property name="relief">none</property>
504 <signal name="clicked" handler="on_forgotten_password_button_clicked"/>450 <property name="uri">foo</property>
451 <signal name="activate-link" handler="on_activate_link" swapped="no"/>
452 <signal name="clicked" handler="on_forgotten_password_button_clicked" swapped="no"/>
505 </object>453 </object>
506 <packing>454 <packing>
507 <property name="expand">False</property>455 <property name="expand">False</property>
@@ -513,20 +461,24 @@
513 </object>461 </object>
514 <packing>462 <packing>
515 <property name="expand">False</property>463 <property name="expand">False</property>
464 <property name="fill">True</property>
516 <property name="position">0</property>465 <property name="position">0</property>
517 </packing>466 </packing>
518 </child>467 </child>
519 <child>468 <child>
520 <object class="GtkHButtonBox" id="hbuttonbox5">469 <object class="GtkHButtonBox" id="hbuttonbox5">
521 <property name="visible">True</property>470 <property name="visible">True</property>
471 <property name="can_focus">False</property>
522 <property name="spacing">5</property>472 <property name="spacing">5</property>
523 <property name="layout_style">end</property>473 <property name="layout_style">end</property>
524 <child>474 <child>
525 <object class="GtkButton" id="login_cancel_button">475 <object class="GtkButton" id="login_cancel_button">
526 <property name="label">gtk-cancel</property>476 <property name="label">gtk-cancel</property>
477 <property name="use_action_appearance">False</property>
527 <property name="visible">True</property>478 <property name="visible">True</property>
528 <property name="can_focus">True</property>479 <property name="can_focus">True</property>
529 <property name="receives_default">True</property>480 <property name="receives_default">True</property>
481 <property name="use_action_appearance">False</property>
530 <property name="use_stock">True</property>482 <property name="use_stock">True</property>
531 </object>483 </object>
532 <packing>484 <packing>
@@ -538,11 +490,13 @@
538 <child>490 <child>
539 <object class="GtkButton" id="login_back_button">491 <object class="GtkButton" id="login_back_button">
540 <property name="label">gtk-go-back</property>492 <property name="label">gtk-go-back</property>
493 <property name="use_action_appearance">False</property>
541 <property name="visible">True</property>494 <property name="visible">True</property>
542 <property name="can_focus">True</property>495 <property name="can_focus">True</property>
543 <property name="receives_default">True</property>496 <property name="receives_default">True</property>
497 <property name="use_action_appearance">False</property>
544 <property name="use_stock">True</property>498 <property name="use_stock">True</property>
545 <signal name="clicked" handler="on_login_back_button_clicked"/>499 <signal name="clicked" handler="on_login_back_button_clicked" swapped="no"/>
546 </object>500 </object>
547 <packing>501 <packing>
548 <property name="expand">False</property>502 <property name="expand">False</property>
@@ -553,11 +507,13 @@
553 <child>507 <child>
554 <object class="GtkButton" id="login_ok_button">508 <object class="GtkButton" id="login_ok_button">
555 <property name="label">gtk-connect</property>509 <property name="label">gtk-connect</property>
510 <property name="use_action_appearance">False</property>
556 <property name="visible">True</property>511 <property name="visible">True</property>
557 <property name="can_focus">True</property>512 <property name="can_focus">True</property>
558 <property name="receives_default">True</property>513 <property name="receives_default">True</property>
514 <property name="use_action_appearance">False</property>
559 <property name="use_stock">True</property>515 <property name="use_stock">True</property>
560 <signal name="clicked" handler="on_login_connect_button_clicked"/>516 <signal name="clicked" handler="on_login_connect_button_clicked" swapped="no"/>
561 </object>517 </object>
562 <packing>518 <packing>
563 <property name="expand">False</property>519 <property name="expand">False</property>
@@ -568,6 +524,7 @@
568 </object>524 </object>
569 <packing>525 <packing>
570 <property name="expand">False</property>526 <property name="expand">False</property>
527 <property name="fill">True</property>
571 <property name="pack_type">end</property>528 <property name="pack_type">end</property>
572 <property name="position">1</property>529 <property name="position">1</property>
573 </packing>530 </packing>
@@ -575,21 +532,33 @@
575 </object>532 </object>
576 <packing>533 <packing>
577 <property name="expand">False</property>534 <property name="expand">False</property>
535 <property name="fill">True</property>
578 <property name="position">1</property>536 <property name="position">1</property>
579 </packing>537 </packing>
580 </child>538 </child>
581 </object>539 </object>
540 <object class="GtkVBox" id="processing_vbox">
541 <property name="visible">True</property>
542 <property name="can_focus">False</property>
543 <property name="spacing">10</property>
544 <child>
545 <placeholder/>
546 </child>
547 </object>
582 <object class="GtkVBox" id="request_password_token_vbox">548 <object class="GtkVBox" id="request_password_token_vbox">
583 <property name="visible">True</property>549 <property name="visible">True</property>
550 <property name="can_focus">False</property>
584 <property name="spacing">10</property>551 <property name="spacing">10</property>
585 <child>552 <child>
586 <object class="GtkAlignment" id="alignment2">553 <object class="GtkAlignment" id="alignment2">
587 <property name="visible">True</property>554 <property name="visible">True</property>
555 <property name="can_focus">False</property>
588 <property name="xscale">0</property>556 <property name="xscale">0</property>
589 <property name="yscale">0</property>557 <property name="yscale">0</property>
590 <child>558 <child>
591 <object class="GtkVBox" id="request_password_token_details_vbox">559 <object class="GtkVBox" id="request_password_token_details_vbox">
592 <property name="visible">True</property>560 <property name="visible">True</property>
561 <property name="can_focus">False</property>
593 <property name="spacing">5</property>562 <property name="spacing">5</property>
594 <child>563 <child>
595 <placeholder/>564 <placeholder/>
@@ -598,20 +567,25 @@
598 </child>567 </child>
599 </object>568 </object>
600 <packing>569 <packing>
570 <property name="expand">True</property>
571 <property name="fill">True</property>
601 <property name="position">0</property>572 <property name="position">0</property>
602 </packing>573 </packing>
603 </child>574 </child>
604 <child>575 <child>
605 <object class="GtkHButtonBox" id="hbuttonbox7">576 <object class="GtkHButtonBox" id="hbuttonbox7">
606 <property name="visible">True</property>577 <property name="visible">True</property>
578 <property name="can_focus">False</property>
607 <property name="spacing">5</property>579 <property name="spacing">5</property>
608 <property name="layout_style">end</property>580 <property name="layout_style">end</property>
609 <child>581 <child>
610 <object class="GtkButton" id="request_password_token_cancel_button">582 <object class="GtkButton" id="request_password_token_cancel_button">
611 <property name="label">gtk-cancel</property>583 <property name="label">gtk-cancel</property>
584 <property name="use_action_appearance">False</property>
612 <property name="visible">True</property>585 <property name="visible">True</property>
613 <property name="can_focus">True</property>586 <property name="can_focus">True</property>
614 <property name="receives_default">True</property>587 <property name="receives_default">True</property>
588 <property name="use_action_appearance">False</property>
615 <property name="use_stock">True</property>589 <property name="use_stock">True</property>
616 </object>590 </object>
617 <packing>591 <packing>
@@ -623,11 +597,13 @@
623 <child>597 <child>
624 <object class="GtkButton" id="request_password_token_back_button">598 <object class="GtkButton" id="request_password_token_back_button">
625 <property name="label">gtk-go-back</property>599 <property name="label">gtk-go-back</property>
600 <property name="use_action_appearance">False</property>
626 <property name="visible">True</property>601 <property name="visible">True</property>
627 <property name="can_focus">True</property>602 <property name="can_focus">True</property>
628 <property name="receives_default">True</property>603 <property name="receives_default">True</property>
604 <property name="use_action_appearance">False</property>
629 <property name="use_stock">True</property>605 <property name="use_stock">True</property>
630 <signal name="clicked" handler="on_request_password_token_back_button_clicked"/>606 <signal name="clicked" handler="on_request_password_token_back_button_clicked" swapped="no"/>
631 </object>607 </object>
632 <packing>608 <packing>
633 <property name="expand">False</property>609 <property name="expand">False</property>
@@ -638,11 +614,13 @@
638 <child>614 <child>
639 <object class="GtkButton" id="request_password_token_ok_button">615 <object class="GtkButton" id="request_password_token_ok_button">
640 <property name="label">gtk-ok</property>616 <property name="label">gtk-ok</property>
617 <property name="use_action_appearance">False</property>
641 <property name="visible">True</property>618 <property name="visible">True</property>
642 <property name="can_focus">True</property>619 <property name="can_focus">True</property>
643 <property name="receives_default">True</property>620 <property name="receives_default">True</property>
621 <property name="use_action_appearance">False</property>
644 <property name="use_stock">True</property>622 <property name="use_stock">True</property>
645 <signal name="clicked" handler="on_request_password_token_ok_button_clicked"/>623 <signal name="clicked" handler="on_request_password_token_ok_button_clicked" swapped="no"/>
646 </object>624 </object>
647 <packing>625 <packing>
648 <property name="expand">False</property>626 <property name="expand">False</property>
@@ -653,35 +631,42 @@
653 </object>631 </object>
654 <packing>632 <packing>
655 <property name="expand">False</property>633 <property name="expand">False</property>
634 <property name="fill">True</property>
656 <property name="position">1</property>635 <property name="position">1</property>
657 </packing>636 </packing>
658 </child>637 </child>
659 </object>638 </object>
660 <object class="GtkVBox" id="set_new_password_vbox">639 <object class="GtkVBox" id="set_new_password_vbox">
661 <property name="visible">True</property>640 <property name="visible">True</property>
641 <property name="can_focus">False</property>
662 <property name="spacing">10</property>642 <property name="spacing">10</property>
663 <child>643 <child>
664 <object class="GtkVBox" id="vbox2">644 <object class="GtkVBox" id="vbox2">
665 <property name="visible">True</property>645 <property name="visible">True</property>
646 <property name="can_focus">False</property>
666 <child>647 <child>
667 <object class="GtkLabel" id="reset_password_help_label">648 <object class="GtkLabel" id="reset_password_help_label">
668 <property name="visible">True</property>649 <property name="visible">True</property>
650 <property name="can_focus">False</property>
669 <property name="label">label</property>651 <property name="label">label</property>
670 <property name="wrap">True</property>652 <property name="wrap">True</property>
671 </object>653 </object>
672 <packing>654 <packing>
673 <property name="expand">False</property>655 <property name="expand">False</property>
656 <property name="fill">True</property>
674 <property name="position">0</property>657 <property name="position">0</property>
675 </packing>658 </packing>
676 </child>659 </child>
677 <child>660 <child>
678 <object class="GtkAlignment" id="alignment1">661 <object class="GtkAlignment" id="alignment1">
679 <property name="visible">True</property>662 <property name="visible">True</property>
663 <property name="can_focus">False</property>
680 <property name="xscale">0</property>664 <property name="xscale">0</property>
681 <property name="yscale">0</property>665 <property name="yscale">0</property>
682 <child>666 <child>
683 <object class="GtkVBox" id="set_new_password_details_vbox">667 <object class="GtkVBox" id="set_new_password_details_vbox">
684 <property name="visible">True</property>668 <property name="visible">True</property>
669 <property name="can_focus">False</property>
685 <property name="spacing">5</property>670 <property name="spacing">5</property>
686 <child>671 <child>
687 <placeholder/>672 <placeholder/>
@@ -696,25 +681,32 @@
696 </child>681 </child>
697 </object>682 </object>
698 <packing>683 <packing>
684 <property name="expand">True</property>
685 <property name="fill">True</property>
699 <property name="position">1</property>686 <property name="position">1</property>
700 </packing>687 </packing>
701 </child>688 </child>
702 </object>689 </object>
703 <packing>690 <packing>
691 <property name="expand">True</property>
692 <property name="fill">True</property>
704 <property name="position">0</property>693 <property name="position">0</property>
705 </packing>694 </packing>
706 </child>695 </child>
707 <child>696 <child>
708 <object class="GtkHButtonBox" id="hbuttonbox6">697 <object class="GtkHButtonBox" id="hbuttonbox6">
709 <property name="visible">True</property>698 <property name="visible">True</property>
699 <property name="can_focus">False</property>
710 <property name="spacing">5</property>700 <property name="spacing">5</property>
711 <property name="layout_style">end</property>701 <property name="layout_style">end</property>
712 <child>702 <child>
713 <object class="GtkButton" id="set_new_password_cancel_button">703 <object class="GtkButton" id="set_new_password_cancel_button">
714 <property name="label">gtk-cancel</property>704 <property name="label">gtk-cancel</property>
705 <property name="use_action_appearance">False</property>
715 <property name="visible">True</property>706 <property name="visible">True</property>
716 <property name="can_focus">True</property>707 <property name="can_focus">True</property>
717 <property name="receives_default">True</property>708 <property name="receives_default">True</property>
709 <property name="use_action_appearance">False</property>
718 <property name="use_stock">True</property>710 <property name="use_stock">True</property>
719 </object>711 </object>
720 <packing>712 <packing>
@@ -726,11 +718,13 @@
726 <child>718 <child>
727 <object class="GtkButton" id="set_new_password_ok_button">719 <object class="GtkButton" id="set_new_password_ok_button">
728 <property name="label">gtk-ok</property>720 <property name="label">gtk-ok</property>
721 <property name="use_action_appearance">False</property>
729 <property name="visible">True</property>722 <property name="visible">True</property>
730 <property name="can_focus">True</property>723 <property name="can_focus">True</property>
731 <property name="receives_default">True</property>724 <property name="receives_default">True</property>
725 <property name="use_action_appearance">False</property>
732 <property name="use_stock">True</property>726 <property name="use_stock">True</property>
733 <signal name="clicked" handler="on_set_new_password_ok_button_clicked"/>727 <signal name="clicked" handler="on_set_new_password_ok_button_clicked" swapped="no"/>
734 </object>728 </object>
735 <packing>729 <packing>
736 <property name="expand">False</property>730 <property name="expand">False</property>
@@ -741,34 +735,104 @@
741 </object>735 </object>
742 <packing>736 <packing>
743 <property name="expand">False</property>737 <property name="expand">False</property>
744 <property name="position">1</property>738 <property name="fill">True</property>
745 </packing>739 <property name="position">1</property>
746 </child>740 </packing>
747 </object>741 </child>
748 <object class="GtkVBox" id="finish_vbox">742 </object>
749 <property name="visible">True</property>743 <object class="GtkVBox" id="tc_browser_vbox">
744 <property name="visible">True</property>
745 <property name="can_focus">False</property>
746 <signal name="hide" handler="on_tc_browser_vbox_hide" swapped="no"/>
747 <child>
748 <object class="GtkScrolledWindow" id="tc_browser_window">
749 <property name="visible">True</property>
750 <property name="can_focus">True</property>
751 <property name="border_width">10</property>
752 <property name="hscrollbar_policy">never</property>
753 <property name="shadow_type">in</property>
754 <child>
755 <placeholder/>
756 </child>
757 </object>
758 <packing>
759 <property name="expand">True</property>
760 <property name="fill">True</property>
761 <property name="position">0</property>
762 </packing>
763 </child>
764 <child>
765 <object class="GtkHButtonBox" id="hbuttonbox4">
766 <property name="visible">True</property>
767 <property name="can_focus">False</property>
768 <property name="layout_style">end</property>
769 <child>
770 <object class="GtkButton" id="tc_back_button">
771 <property name="label">gtk-go-back</property>
772 <property name="use_action_appearance">False</property>
773 <property name="visible">True</property>
774 <property name="can_focus">True</property>
775 <property name="receives_default">True</property>
776 <property name="use_action_appearance">False</property>
777 <property name="use_stock">True</property>
778 <signal name="clicked" handler="on_tc_back_button_clicked" swapped="no"/>
779 </object>
780 <packing>
781 <property name="expand">False</property>
782 <property name="fill">False</property>
783 <property name="position">0</property>
784 </packing>
785 </child>
786 </object>
787 <packing>
788 <property name="expand">False</property>
789 <property name="fill">True</property>
790 <property name="position">1</property>
791 </packing>
792 </child>
793 </object>
794 <object class="GtkVBox" id="verify_email_vbox">
795 <property name="visible">True</property>
796 <property name="can_focus">False</property>
750 <property name="spacing">10</property>797 <property name="spacing">10</property>
751 <child>798 <child>
752 <object class="GtkLabel" id="finish_label">799 <object class="GtkAlignment" id="alignment4">
753 <property name="visible">True</property>800 <property name="visible">True</property>
754 <property name="wrap">True</property>801 <property name="can_focus">False</property>
802 <property name="xscale">0</property>
803 <property name="yscale">0</property>
804 <child>
805 <object class="GtkVBox" id="verify_email_details_vbox">
806 <property name="visible">True</property>
807 <property name="can_focus">False</property>
808 <child>
809 <placeholder/>
810 </child>
811 </object>
812 </child>
755 </object>813 </object>
756 <packing>814 <packing>
815 <property name="expand">True</property>
816 <property name="fill">True</property>
757 <property name="position">0</property>817 <property name="position">0</property>
758 </packing>818 </packing>
759 </child>819 </child>
760 <child>820 <child>
761 <object class="GtkHButtonBox" id="hbuttonbox8">821 <object class="GtkHButtonBox" id="hbuttonbox2">
762 <property name="visible">True</property>822 <property name="visible">True</property>
823 <property name="can_focus">False</property>
824 <property name="spacing">5</property>
763 <property name="layout_style">end</property>825 <property name="layout_style">end</property>
764 <child>826 <child>
765 <object class="GtkButton" id="finish_close_button">827 <object class="GtkButton" id="verify_token_button">
766 <property name="label">gtk-close</property>828 <property name="label">gtk-ok</property>
829 <property name="use_action_appearance">False</property>
767 <property name="visible">True</property>830 <property name="visible">True</property>
768 <property name="can_focus">True</property>831 <property name="can_focus">True</property>
769 <property name="receives_default">True</property>832 <property name="receives_default">True</property>
833 <property name="use_action_appearance">False</property>
770 <property name="use_stock">True</property>834 <property name="use_stock">True</property>
771 <signal name="clicked" handler="on_close_clicked"/>835 <signal name="clicked" handler="on_verify_token_button_clicked" swapped="no"/>
772 </object>836 </object>
773 <packing>837 <packing>
774 <property name="expand">False</property>838 <property name="expand">False</property>
@@ -779,8 +843,78 @@
779 </object>843 </object>
780 <packing>844 <packing>
781 <property name="expand">False</property>845 <property name="expand">False</property>
846 <property name="fill">True</property>
782 <property name="position">1</property>847 <property name="position">1</property>
783 </packing>848 </packing>
784 </child>849 </child>
785 </object>850 </object>
851 <object class="GtkWindow" id="window">
852 <property name="can_focus">False</property>
853 <property name="border_width">10</property>
854 <property name="window_position">center</property>
855 <signal name="delete-event" handler="on_close_clicked" swapped="no"/>
856 <child>
857 <object class="GtkVBox" id="window_vbox">
858 <property name="visible">True</property>
859 <property name="can_focus">False</property>
860 <property name="spacing">5</property>
861 <child>
862 <object class="GtkLabel" id="header_label">
863 <property name="visible">True</property>
864 <property name="can_focus">False</property>
865 <property name="xalign">0</property>
866 <property name="label" translatable="yes">Header Label </property>
867 <property name="wrap">True</property>
868 </object>
869 <packing>
870 <property name="expand">False</property>
871 <property name="fill">True</property>
872 <property name="padding">5</property>
873 <property name="position">0</property>
874 </packing>
875 </child>
876 <child>
877 <object class="GtkLabel" id="help_label">
878 <property name="visible">True</property>
879 <property name="can_focus">False</property>
880 <property name="xalign">0</property>
881 <property name="label" translatable="yes">help label</property>
882 <property name="wrap">True</property>
883 </object>
884 <packing>
885 <property name="expand">False</property>
886 <property name="fill">True</property>
887 <property name="position">1</property>
888 </packing>
889 </child>
890 <child>
891 <object class="GtkLabel" id="warning_label">
892 <property name="visible">True</property>
893 <property name="can_focus">False</property>
894 <property name="xalign">0</property>
895 <property name="label" translatable="yes">warning label</property>
896 <property name="wrap">True</property>
897 </object>
898 <packing>
899 <property name="expand">False</property>
900 <property name="fill">True</property>
901 <property name="position">2</property>
902 </packing>
903 </child>
904 <child>
905 <object class="GtkNotebook" id="content">
906 <property name="visible">True</property>
907 <property name="can_focus">True</property>
908 <property name="show_tabs">False</property>
909 <property name="show_border">False</property>
910 </object>
911 <packing>
912 <property name="expand">True</property>
913 <property name="fill">True</property>
914 <property name="position">3</property>
915 </packing>
916 </child>
917 </object>
918 </child>
919 </object>
786</interface>920</interface>
787921
=== modified file 'data/qt/choose_sign_in.ui'
--- data/qt/choose_sign_in.ui 2011-04-05 14:04:50 +0000
+++ data/qt/choose_sign_in.ui 2012-02-14 22:04:20 +0000
@@ -1,32 +1,103 @@
1<?xml version="1.0" encoding="UTF-8"?>1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">2<ui version="4.0">
3 <class>ChooseSignInPage</class>3 <class>ChooseSignInPage</class>
4 <widget class="QWizardPage" name="ChooseSingInPage">4 <widget class="QWizardPage" name="ChooseSignInPage">
5 <property name="geometry">5 <property name="geometry">
6 <rect>6 <rect>
7 <x>0</x>7 <x>0</x>
8 <y>0</y>8 <y>0</y>
9 <width>400</width>9 <width>432</width>
10 <height>300</height>10 <height>387</height>
11 </rect>11 </rect>
12 </property>12 </property>
13 <property name="windowTitle">13 <property name="windowTitle">
14 <string>WizardPage</string>14 <string>WizardPage</string>
15 </property>15 </property>
16 <layout class="QHBoxLayout" name="horizontalLayout">16 <layout class="QVBoxLayout" name="verticalLayout_2">
17 <item>17 <property name="leftMargin">
18 <layout class="QHBoxLayout" name="horizontalLayout_3">18 <number>0</number>
19 </property>
20 <property name="topMargin">
21 <number>0</number>
22 </property>
23 <property name="rightMargin">
24 <number>0</number>
25 </property>
26 <item>
27 <layout class="QHBoxLayout" name="horizontalLayout_2">
28 <item>
29 <widget class="QLabel" name="image_label">
30 <property name="sizePolicy">
31 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
32 <horstretch>0</horstretch>
33 <verstretch>0</verstretch>
34 </sizepolicy>
35 </property>
36 <property name="minimumSize">
37 <size>
38 <width>400</width>
39 <height>150</height>
40 </size>
41 </property>
42 <property name="text">
43 <string/>
44 </property>
45 <property name="textFormat">
46 <enum>Qt::PlainText</enum>
47 </property>
48 <property name="alignment">
49 <set>Qt::AlignCenter</set>
50 </property>
51 <property name="wordWrap">
52 <bool>true</bool>
53 </property>
54 </widget>
55 </item>
56 </layout>
57 </item>
58 <item>
59 <widget class="QLabel" name="message_label">
60 <property name="font">
61 <font>
62 <pointsize>11</pointsize>
63 <weight>50</weight>
64 <bold>false</bold>
65 </font>
66 </property>
67 <property name="text">
68 <string>Congratulations, app_name is installed!</string>
69 </property>
70 <property name="alignment">
71 <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
72 </property>
73 </widget>
74 </item>
75 <item>
76 <spacer name="verticalSpacer_3">
77 <property name="orientation">
78 <enum>Qt::Vertical</enum>
79 </property>
80 <property name="sizeType">
81 <enum>QSizePolicy::Fixed</enum>
82 </property>
83 <property name="sizeHint" stdset="0">
84 <size>
85 <width>20</width>
86 <height>30</height>
87 </size>
88 </property>
89 </spacer>
90 </item>
91 <item>
92 <layout class="QHBoxLayout" name="horizontalLayout">
19 <item>93 <item>
20 <spacer name="horizontalSpacer_2">94 <spacer name="horizontalSpacer_2">
21 <property name="orientation">95 <property name="orientation">
22 <enum>Qt::Horizontal</enum>96 <enum>Qt::Horizontal</enum>
23 </property>97 </property>
24 <property name="sizeType">
25 <enum>QSizePolicy::Expanding</enum>
26 </property>
27 <property name="sizeHint" stdset="0">98 <property name="sizeHint" stdset="0">
28 <size>99 <size>
29 <width>40</width>100 <width>20</width>
30 <height>20</height>101 <height>20</height>
31 </size>102 </size>
32 </property>103 </property>
@@ -35,44 +106,11 @@
35 <item>106 <item>
36 <layout class="QVBoxLayout" name="verticalLayout">107 <layout class="QVBoxLayout" name="verticalLayout">
37 <item>108 <item>
38 <spacer name="verticalSpacer_3">109 <widget class="QPushButton" name="existing_account_button">
39 <property name="orientation">110 <property name="text">
40 <enum>Qt::Vertical</enum>111 <string/>
41 </property>112 </property>
42 <property name="sizeHint" stdset="0">113 </widget>
43 <size>
44 <width>20</width>
45 <height>40</height>
46 </size>
47 </property>
48 </spacer>
49 </item>
50 <item>
51 <layout class="QHBoxLayout" name="horizontalLayout_2">
52 <item>
53 <widget class="QPushButton" name="existing_account_button">
54 <property name="text">
55 <string/>
56 </property>
57 </widget>
58 </item>
59 </layout>
60 </item>
61 <item>
62 <spacer name="verticalSpacer">
63 <property name="orientation">
64 <enum>Qt::Vertical</enum>
65 </property>
66 <property name="sizeType">
67 <enum>QSizePolicy::Fixed</enum>
68 </property>
69 <property name="sizeHint" stdset="0">
70 <size>
71 <width>20</width>
72 <height>10</height>
73 </size>
74 </property>
75 </spacer>
76 </item>114 </item>
77 <item>115 <item>
78 <widget class="QPushButton" name="setup_account_button">116 <widget class="QPushButton" name="setup_account_button">
@@ -82,17 +120,11 @@
82 </widget>120 </widget>
83 </item>121 </item>
84 <item>122 <item>
85 <spacer name="verticalSpacer_2">123 <widget class="QPushButton" name="cancel_button">
86 <property name="orientation">124 <property name="text">
87 <enum>Qt::Vertical</enum>125 <string/>
88 </property>126 </property>
89 <property name="sizeHint" stdset="0">127 </widget>
90 <size>
91 <width>20</width>
92 <height>40</height>
93 </size>
94 </property>
95 </spacer>
96 </item>128 </item>
97 </layout>129 </layout>
98 </item>130 </item>
@@ -106,7 +138,7 @@
106 </property>138 </property>
107 <property name="sizeHint" stdset="0">139 <property name="sizeHint" stdset="0">
108 <size>140 <size>
109 <width>40</width>141 <width>20</width>
110 <height>20</height>142 <height>20</height>
111 </size>143 </size>
112 </property>144 </property>
@@ -114,8 +146,20 @@
114 </item>146 </item>
115 </layout>147 </layout>
116 </item>148 </item>
149 <item>
150 <spacer name="verticalSpacer_2">
151 <property name="orientation">
152 <enum>Qt::Vertical</enum>
153 </property>
154 <property name="sizeHint" stdset="0">
155 <size>
156 <width>20</width>
157 <height>50</height>
158 </size>
159 </property>
160 </spacer>
161 </item>
117 </layout>162 </layout>
118 </widget>163 </widget>
119 <resources/>
120 <connections/>164 <connections/>
121</ui>165</ui>
122166
=== added file 'data/qt/loadingoverlay.ui'
--- data/qt/loadingoverlay.ui 1970-01-01 00:00:00 +0000
+++ data/qt/loadingoverlay.ui 2012-02-14 22:04:20 +0000
@@ -0,0 +1,103 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>Form</class>
4 <widget class="QFrame" name="Form">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>702</width>
10 <height>230</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Frame</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout">
17 <property name="topMargin">
18 <number>30</number>
19 </property>
20 <item>
21 <layout class="QHBoxLayout" name="horizontalLayout_2">
22 <item>
23 <spacer name="horizontalSpacer_2">
24 <property name="orientation">
25 <enum>Qt::Horizontal</enum>
26 </property>
27 <property name="sizeHint" stdset="0">
28 <size>
29 <width>40</width>
30 <height>20</height>
31 </size>
32 </property>
33 </spacer>
34 </item>
35 <item>
36 <widget class="QFrame" name="frm_box">
37 <property name="minimumSize">
38 <size>
39 <width>0</width>
40 <height>102</height>
41 </size>
42 </property>
43 <layout class="QHBoxLayout" name="horizontalLayout">
44 <property name="topMargin">
45 <number>0</number>
46 </property>
47 <property name="bottomMargin">
48 <number>30</number>
49 </property>
50 <item>
51 <widget class="QLabel" name="label">
52 <property name="sizePolicy">
53 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
54 <horstretch>0</horstretch>
55 <verstretch>0</verstretch>
56 </sizepolicy>
57 </property>
58 <property name="font">
59 <font>
60 <pointsize>14</pointsize>
61 </font>
62 </property>
63 <property name="text">
64 <string>Getting information, please wait...</string>
65 </property>
66 </widget>
67 </item>
68 </layout>
69 </widget>
70 </item>
71 <item>
72 <spacer name="horizontalSpacer">
73 <property name="orientation">
74 <enum>Qt::Horizontal</enum>
75 </property>
76 <property name="sizeHint" stdset="0">
77 <size>
78 <width>40</width>
79 <height>20</height>
80 </size>
81 </property>
82 </spacer>
83 </item>
84 </layout>
85 </item>
86 <item>
87 <spacer name="verticalSpacer">
88 <property name="orientation">
89 <enum>Qt::Vertical</enum>
90 </property>
91 <property name="sizeHint" stdset="0">
92 <size>
93 <width>20</width>
94 <height>20</height>
95 </size>
96 </property>
97 </spacer>
98 </item>
99 </layout>
100 </widget>
101 <resources/>
102 <connections/>
103</ui>
0104
=== added file 'data/qt/network_detection.ui'
--- data/qt/network_detection.ui 1970-01-01 00:00:00 +0000
+++ data/qt/network_detection.ui 2012-02-14 22:04:20 +0000
@@ -0,0 +1,142 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>Form</class>
4 <widget class="QWizardPage" name="Form">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>541</width>
10 <height>365</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>WizardPage</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout">
17 <item>
18 <layout class="QHBoxLayout" name="horizontalLayout_2">
19 <item>
20 <spacer name="horizontalSpacer_3">
21 <property name="orientation">
22 <enum>Qt::Horizontal</enum>
23 </property>
24 <property name="sizeHint" stdset="0">
25 <size>
26 <width>40</width>
27 <height>20</height>
28 </size>
29 </property>
30 </spacer>
31 </item>
32 <item>
33 <widget class="QLabel" name="image_label">
34 <property name="sizePolicy">
35 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
36 <horstretch>0</horstretch>
37 <verstretch>0</verstretch>
38 </sizepolicy>
39 </property>
40 <property name="minimumSize">
41 <size>
42 <width>400</width>
43 <height>150</height>
44 </size>
45 </property>
46 <property name="text">
47 <string/>
48 </property>
49 <property name="textFormat">
50 <enum>Qt::PlainText</enum>
51 </property>
52 <property name="alignment">
53 <set>Qt::AlignCenter</set>
54 </property>
55 <property name="wordWrap">
56 <bool>true</bool>
57 </property>
58 </widget>
59 </item>
60 <item>
61 <spacer name="horizontalSpacer_4">
62 <property name="orientation">
63 <enum>Qt::Horizontal</enum>
64 </property>
65 <property name="sizeHint" stdset="0">
66 <size>
67 <width>40</width>
68 <height>20</height>
69 </size>
70 </property>
71 </spacer>
72 </item>
73 </layout>
74 </item>
75 <item>
76 <widget class="QLabel" name="message_label">
77 <property name="alignment">
78 <set>Qt::AlignCenter</set>
79 </property>
80 </widget>
81 </item>
82 <item>
83 <layout class="QHBoxLayout" name="horizontalLayout">
84 <item>
85 <spacer name="horizontalSpacer">
86 <property name="orientation">
87 <enum>Qt::Horizontal</enum>
88 </property>
89 <property name="sizeHint" stdset="0">
90 <size>
91 <width>40</width>
92 <height>20</height>
93 </size>
94 </property>
95 </spacer>
96 </item>
97 <item>
98 <widget class="QLabel" name="label">
99 <property name="text">
100 <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>
101 </property>
102 <property name="textFormat">
103 <enum>Qt::PlainText</enum>
104 </property>
105 <property name="wordWrap">
106 <bool>true</bool>
107 </property>
108 </widget>
109 </item>
110 <item>
111 <spacer name="horizontalSpacer_2">
112 <property name="orientation">
113 <enum>Qt::Horizontal</enum>
114 </property>
115 <property name="sizeHint" stdset="0">
116 <size>
117 <width>40</width>
118 <height>20</height>
119 </size>
120 </property>
121 </spacer>
122 </item>
123 </layout>
124 </item>
125 <item>
126 <spacer name="verticalSpacer">
127 <property name="orientation">
128 <enum>Qt::Vertical</enum>
129 </property>
130 <property name="sizeHint" stdset="0">
131 <size>
132 <width>20</width>
133 <height>76</height>
134 </size>
135 </property>
136 </spacer>
137 </item>
138 </layout>
139 </widget>
140 <resources/>
141 <connections/>
142</ui>
0143
=== added file 'data/qt/proxy_credentials_dialog.ui'
--- data/qt/proxy_credentials_dialog.ui 1970-01-01 00:00:00 +0000
+++ data/qt/proxy_credentials_dialog.ui 2012-02-14 22:04:20 +0000
@@ -0,0 +1,316 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ProxyCredsDialog</class>
4 <widget class="QDialog" name="ProxyCredsDialog">
5 <property name="windowModality">
6 <enum>Qt::NonModal</enum>
7 </property>
8 <property name="geometry">
9 <rect>
10 <x>0</x>
11 <y>0</y>
12 <width>550</width>
13 <height>364</height>
14 </rect>
15 </property>
16 <property name="sizePolicy">
17 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
18 <horstretch>0</horstretch>
19 <verstretch>0</verstretch>
20 </sizepolicy>
21 </property>
22 <property name="minimumSize">
23 <size>
24 <width>502</width>
25 <height>0</height>
26 </size>
27 </property>
28 <property name="windowTitle">
29 <string>Add proxy settings</string>
30 </property>
31 <property name="sizeGripEnabled">
32 <bool>false</bool>
33 </property>
34 <layout class="QHBoxLayout" name="horizontalLayout">
35 <property name="sizeConstraint">
36 <enum>QLayout::SetFixedSize</enum>
37 </property>
38 <item>
39 <layout class="QVBoxLayout" name="verticalLayout">
40 <property name="spacing">
41 <number>24</number>
42 </property>
43 <item>
44 <layout class="QHBoxLayout" name="horizontalLayout_4">
45 <property name="spacing">
46 <number>12</number>
47 </property>
48 <item>
49 <layout class="QVBoxLayout" name="verticalLayout_4">
50 <property name="spacing">
51 <number>0</number>
52 </property>
53 <property name="sizeConstraint">
54 <enum>QLayout::SetDefaultConstraint</enum>
55 </property>
56 <item>
57 <widget class="QLabel" name="logo_label">
58 <property name="sizePolicy">
59 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
60 <horstretch>0</horstretch>
61 <verstretch>0</verstretch>
62 </sizepolicy>
63 </property>
64 <property name="minimumSize">
65 <size>
66 <width>48</width>
67 <height>48</height>
68 </size>
69 </property>
70 <property name="maximumSize">
71 <size>
72 <width>48</width>
73 <height>48</height>
74 </size>
75 </property>
76 <property name="text">
77 <string>TextLabel</string>
78 </property>
79 </widget>
80 </item>
81 <item>
82 <spacer name="verticalSpacer_4">
83 <property name="orientation">
84 <enum>Qt::Vertical</enum>
85 </property>
86 <property name="sizeType">
87 <enum>QSizePolicy::Expanding</enum>
88 </property>
89 <property name="sizeHint" stdset="0">
90 <size>
91 <width>0</width>
92 <height>20</height>
93 </size>
94 </property>
95 </spacer>
96 </item>
97 </layout>
98 </item>
99 <item>
100 <layout class="QVBoxLayout" name="verticalLayout_3">
101 <property name="spacing">
102 <number>24</number>
103 </property>
104 <item>
105 <layout class="QVBoxLayout" name="verticalLayout_2">
106 <property name="spacing">
107 <number>24</number>
108 </property>
109 <item>
110 <widget class="QLabel" name="title_label">
111 <property name="sizePolicy">
112 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
113 <horstretch>0</horstretch>
114 <verstretch>0</verstretch>
115 </sizepolicy>
116 </property>
117 <property name="font">
118 <font>
119 <pointsize>14</pointsize>
120 <weight>75</weight>
121 <bold>true</bold>
122 </font>
123 </property>
124 <property name="text">
125 <string>You are connection through a proxy.</string>
126 </property>
127 <property name="wordWrap">
128 <bool>true</bool>
129 </property>
130 </widget>
131 </item>
132 <item>
133 <widget class="QLabel" name="explanation_label">
134 <property name="text">
135 <string>Please provide the login details below, or check your system settings</string>
136 </property>
137 <property name="wordWrap">
138 <bool>true</bool>
139 </property>
140 </widget>
141 </item>
142 </layout>
143 </item>
144 <item>
145 <widget class="QFrame" name="frame">
146 <property name="frameShape">
147 <enum>QFrame::NoFrame</enum>
148 </property>
149 <property name="frameShadow">
150 <enum>QFrame::Plain</enum>
151 </property>
152 <layout class="QGridLayout" name="gridLayout_2">
153 <property name="spacing">
154 <number>12</number>
155 </property>
156 <item row="0" column="0">
157 <widget class="QLabel" name="connection_label">
158 <property name="sizePolicy">
159 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
160 <horstretch>0</horstretch>
161 <verstretch>0</verstretch>
162 </sizepolicy>
163 </property>
164 <property name="text">
165 <string>Connecting to:</string>
166 </property>
167 <property name="alignment">
168 <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
169 </property>
170 </widget>
171 </item>
172 <item row="0" column="1">
173 <widget class="QLabel" name="domain_label">
174 <property name="text">
175 <string/>
176 </property>
177 </widget>
178 </item>
179 <item row="4" column="0">
180 <widget class="QLabel" name="username_label">
181 <property name="text">
182 <string>Proxy username:</string>
183 </property>
184 <property name="alignment">
185 <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
186 </property>
187 </widget>
188 </item>
189 <item row="4" column="1">
190 <widget class="QLineEdit" name="username_entry">
191 <property name="text">
192 <string/>
193 </property>
194 </widget>
195 </item>
196 <item row="5" column="0">
197 <widget class="QLabel" name="password_label">
198 <property name="text">
199 <string>Proxy password:</string>
200 </property>
201 <property name="alignment">
202 <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
203 </property>
204 </widget>
205 </item>
206 <item row="5" column="1">
207 <widget class="QLineEdit" name="password_entry">
208 <property name="echoMode">
209 <enum>QLineEdit::Password</enum>
210 </property>
211 </widget>
212 </item>
213 <item row="1" column="0">
214 <spacer name="verticalSpacer">
215 <property name="orientation">
216 <enum>Qt::Vertical</enum>
217 </property>
218 <property name="sizeType">
219 <enum>QSizePolicy::Fixed</enum>
220 </property>
221 <property name="sizeHint" stdset="0">
222 <size>
223 <width>24</width>
224 <height>12</height>
225 </size>
226 </property>
227 </spacer>
228 </item>
229 <item row="2" column="0" colspan="2">
230 <widget class="QLabel" name="error_label">
231 <property name="text">
232 <string>TextLabel</string>
233 </property>
234 <property name="wordWrap">
235 <bool>false</bool>
236 </property>
237 </widget>
238 </item>
239 <item row="3" column="0">
240 <spacer name="verticalSpacer_2">
241 <property name="orientation">
242 <enum>Qt::Vertical</enum>
243 </property>
244 <property name="sizeType">
245 <enum>QSizePolicy::Fixed</enum>
246 </property>
247 <property name="sizeHint" stdset="0">
248 <size>
249 <width>24</width>
250 <height>12</height>
251 </size>
252 </property>
253 </spacer>
254 </item>
255 </layout>
256 </widget>
257 </item>
258 </layout>
259 </item>
260 </layout>
261 </item>
262 <item>
263 <layout class="QHBoxLayout" name="horizontalLayout_5">
264 <item>
265 <widget class="QPushButton" name="help_button">
266 <property name="text">
267 <string>Get Help With Proxies</string>
268 </property>
269 </widget>
270 </item>
271 <item>
272 <spacer name="horizontalSpacer">
273 <property name="orientation">
274 <enum>Qt::Horizontal</enum>
275 </property>
276 <property name="sizeHint" stdset="0">
277 <size>
278 <width>40</width>
279 <height>20</height>
280 </size>
281 </property>
282 </spacer>
283 </item>
284 <item>
285 <widget class="QPushButton" name="cancel_button">
286 <property name="text">
287 <string>Cancel and Close</string>
288 </property>
289 </widget>
290 </item>
291 <item>
292 <widget class="QPushButton" name="save_button">
293 <property name="text">
294 <string>Save</string>
295 </property>
296 <property name="default">
297 <bool>true</bool>
298 </property>
299 </widget>
300 </item>
301 </layout>
302 </item>
303 </layout>
304 </item>
305 </layout>
306 </widget>
307 <tabstops>
308 <tabstop>username_entry</tabstop>
309 <tabstop>password_entry</tabstop>
310 <tabstop>save_button</tabstop>
311 <tabstop>cancel_button</tabstop>
312 <tabstop>help_button</tabstop>
313 </tabstops>
314 <resources/>
315 <connections/>
316</ui>
0317
=== modified file 'data/qt/setup_account.ui'
--- data/qt/setup_account.ui 2011-09-02 12:53:55 +0000
+++ data/qt/setup_account.ui 2012-02-14 22:04:20 +0000
@@ -6,275 +6,662 @@
6 <rect>6 <rect>
7 <x>0</x>7 <x>0</x>
8 <y>0</y>8 <y>0</y>
9 <width>407</width>9 <width>543</width>
10 <height>572</height>10 <height>523</height>
11 </rect>11 </rect>
12 </property>12 </property>
13 <property name="sizePolicy">
14 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
15 <horstretch>0</horstretch>
16 <verstretch>0</verstretch>
17 </sizepolicy>
18 </property>
19 <property name="maximumSize">
20 <size>
21 <width>16777215</width>
22 <height>16777215</height>
23 </size>
24 </property>
13 <property name="windowTitle">25 <property name="windowTitle">
14 <string>WizardPage</string>26 <string>WizardPage</string>
15 </property>27 </property>
16 <layout class="QVBoxLayout" name="verticalLayout_5">28 <layout class="QVBoxLayout" name="verticalLayout">
29 <property name="spacing">
30 <number>0</number>
31 </property>
32 <property name="leftMargin">
33 <number>0</number>
34 </property>
17 <property name="topMargin">35 <property name="topMargin">
18 <number>0</number>36 <number>0</number>
19 </property>37 </property>
38 <property name="rightMargin">
39 <number>3</number>
40 </property>
41 <property name="bottomMargin">
42 <number>0</number>
43 </property>
20 <item>44 <item>
21 <layout class="QVBoxLayout" name="verticalLayout">45 <layout class="QGridLayout" name="gridLayout" columnminimumwidth="310,220">
22 <item>46 <item row="0" column="0">
23 <widget class="QFrame" name="_signInFrame">47 <widget class="QLabel" name="password_info_label">
24 <property name="frameShape">48 <property name="sizePolicy">
25 <enum>QFrame::NoFrame</enum>49 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
26 </property>50 <horstretch>0</horstretch>
27 <layout class="QVBoxLayout" name="verticalLayout_3">51 <verstretch>0</verstretch>
28 <item>52 </sizepolicy>
29 <layout class="QVBoxLayout" name="verticalLayout_2">53 </property>
30 <item>54 <property name="text">
31 <widget class="QLabel" name="password_info_label">55 <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>
32 <property name="sizePolicy">56 </property>
33 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">57 <property name="wordWrap">
34 <horstretch>0</horstretch>58 <bool>true</bool>
35 <verstretch>0</verstretch>59 </property>
36 </sizepolicy>60 </widget>
37 </property>61 </item>
38 <property name="text">62 <item row="1" column="0">
39 <string/>63 <layout class="QVBoxLayout" name="verticalLayout">
40 </property>64 <property name="spacing">
41 <property name="wordWrap">65 <number>3</number>
42 <bool>true</bool>66 </property>
43 </property>67 <item>
44 </widget>68 <widget class="QLabel" name="name_label">
45 </item>69 <property name="font">
46 <item>70 <font>
47 <layout class="QVBoxLayout" name="verticalLayout_4">71 <weight>75</weight>
48 <item>72 <bold>true</bold>
49 <widget class="QLabel" name="name_label">73 </font>
50 <property name="text">74 </property>
51 <string/>75 <property name="text">
52 </property>76 <string>name_label</string>
53 </widget>77 </property>
54 </item>78 </widget>
55 <item>79 </item>
56 <widget class="QLineEdit" name="name_edit">80 <item>
57 <property name="placeholderText">81 <widget class="QLineEdit" name="name_edit">
58 <string/>82 <property name="sizePolicy">
59 </property>83 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
60 </widget>84 <horstretch>0</horstretch>
61 </item>85 <verstretch>0</verstretch>
62 <item>86 </sizepolicy>
63 <widget class="QLabel" name="email_label">87 </property>
64 <property name="text">88 <property name="minimumSize">
65 <string/>89 <size>
66 </property>90 <width>300</width>
67 </widget>91 <height>0</height>
68 </item>92 </size>
69 <item>93 </property>
70 <widget class="QLineEdit" name="email_edit">94 <property name="maximumSize">
71 <property name="placeholderText">95 <size>
72 <string/>96 <width>300</width>
73 </property>97 <height>16777215</height>
74 </widget>98 </size>
75 </item>99 </property>
76 <item>100 <property name="font">
77 <widget class="QLabel" name="confirm_email_label">101 <font>
78 <property name="text">102 <pointsize>11</pointsize>
79 <string/>103 </font>
80 </property>104 </property>
81 </widget>105 <property name="formError" stdset="0">
82 </item>106 <bool>false</bool>
83 <item>107 </property>
84 <widget class="QLineEdit" name="confirm_email_edit">108 </widget>
85 <property name="placeholderText">109 </item>
86 <string/>110 </layout>
87 </property>111 </item>
88 </widget>112 <item row="3" column="0">
89 </item>113 <layout class="QVBoxLayout" name="verticalLayout">
90 <item>114 <property name="spacing">
91 <widget class="QLabel" name="password_label">115 <number>3</number>
92 <property name="text">116 </property>
93 <string/>117 <item>
94 </property>118 <widget class="QLabel" name="email_label">
95 </widget>119 <property name="font">
96 </item>120 <font>
97 <item>121 <weight>75</weight>
98 <widget class="QLineEdit" name="password_edit">122 <bold>true</bold>
99 <property name="toolTip">123 </font>
100 <string>Your password must be at least 8 characters long and at least contain one number and one upper later.</string>124 </property>
101 </property>125 <property name="text">
102 <property name="statusTip">126 <string>email_label</string>
103 <string/>127 </property>
104 </property>128 </widget>
105 <property name="echoMode">129 </item>
106 <enum>QLineEdit::Password</enum>130 <item>
107 </property>131 <widget class="QLineEdit" name="email_edit">
108 <property name="placeholderText">132 <property name="sizePolicy">
109 <string/>133 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
110 </property>134 <horstretch>0</horstretch>
111 </widget>135 <verstretch>0</verstretch>
112 </item>136 </sizepolicy>
113 <item>137 </property>
114 <widget class="QLabel" name="confirm_password_label">138 <property name="minimumSize">
115 <property name="text">139 <size>
116 <string/>140 <width>300</width>
117 </property>141 <height>0</height>
118 </widget>142 </size>
119 </item>143 </property>
120 <item>144 <property name="maximumSize">
121 <widget class="QLineEdit" name="confirm_password_edit">145 <size>
122 <property name="echoMode">146 <width>300</width>
123 <enum>QLineEdit::Password</enum>147 <height>16777215</height>
124 </property>148 </size>
125 <property name="placeholderText">149 </property>
126 <string/>150 <property name="font">
127 </property>151 <font>
128 </widget>152 <pointsize>11</pointsize>
129 </item>153 </font>
130 </layout>154 </property>
131 </item>155 <property name="placeholderText">
132 <item>156 <string/>
133 <layout class="QVBoxLayout" name="verticalLayout_9">157 </property>
134 <item>158 <property name="formError" stdset="0">
135 <widget class="QFrame" name="frame_2">159 <bool>false</bool>
136 <property name="sizePolicy">160 </property>
137 <sizepolicy hsizetype="Minimum" vsizetype="Minimum">161 </widget>
138 <horstretch>0</horstretch>162 </item>
139 <verstretch>0</verstretch>163 </layout>
140 </sizepolicy>164 </item>
141 </property>165 <item row="4" column="0">
142 <property name="frameShape">166 <layout class="QVBoxLayout" name="verticalLayout">
143 <enum>QFrame::StyledPanel</enum>167 <property name="spacing">
144 </property>168 <number>3</number>
145 <property name="frameShadow">169 </property>
146 <enum>QFrame::Raised</enum>170 <item>
147 </property>171 <widget class="QLabel" name="confirm_email_label">
148 <layout class="QHBoxLayout" name="horizontalLayout_16">172 <property name="font">
149 <property name="leftMargin">173 <font>
150 <number>0</number>174 <weight>75</weight>
151 </property>175 <bold>true</bold>
152 <item>176 </font>
153 <widget class="QLabel" name="captcha_view">177 </property>
154 <property name="minimumSize">178 <property name="text">
155 <size>179 <string>confirm_email_label</string>
156 <width>0</width>180 </property>
157 <height>57</height>181 </widget>
158 </size>182 </item>
159 </property>183 <item>
160 <property name="frameShape">184 <widget class="QLineEdit" name="confirm_email_edit">
161 <enum>QFrame::Box</enum>185 <property name="sizePolicy">
162 </property>186 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
163 <property name="text">187 <horstretch>0</horstretch>
164 <string/>188 <verstretch>0</verstretch>
165 </property>189 </sizepolicy>
166 </widget>190 </property>
167 </item>191 <property name="minimumSize">
168 <item>192 <size>
169 <widget class="QLabel" name="refresh_label">193 <width>300</width>
170 <property name="sizePolicy">194 <height>0</height>
171 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">195 </size>
172 <horstretch>0</horstretch>196 </property>
173 <verstretch>0</verstretch>197 <property name="maximumSize">
174 </sizepolicy>198 <size>
175 </property>199 <width>300</width>
176 <property name="locale">200 <height>16777215</height>
177 <locale language="English" country="UnitedStates"/>201 </size>
178 </property>202 </property>
179 <property name="text">203 <property name="font">
180 <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;204 <font>
181&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;205 <pointsize>11</pointsize>
182p, li { white-space: pre-wrap; }206 </font>
183&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;207 </property>
184&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>208 <property name="placeholderText">
185 </property>209 <string/>
186 <property name="wordWrap">210 </property>
187 <bool>true</bool>211 <property name="formError" stdset="0">
188 </property>212 <bool>false</bool>
189 </widget>213 </property>
190 </item>214 </widget>
191 </layout>215 </item>
192 </widget>216 </layout>
193 </item>217 </item>
194 <item>218 <item row="6" column="0">
195 <widget class="QLineEdit" name="captcha_solution_edit">219 <layout class="QVBoxLayout" name="verticalLayout">
196 <property name="locale">220 <property name="spacing">
197 <locale language="English" country="UnitedStates"/>221 <number>3</number>
198 </property>222 </property>
199 <property name="inputMask">223 <item>
200 <string/>224 <widget class="QLabel" name="password_label">
201 </property>225 <property name="font">
202 <property name="text">226 <font>
203 <string/>227 <weight>75</weight>
204 </property>228 <bold>true</bold>
205 <property name="placeholderText">229 </font>
206 <string/>230 </property>
207 </property>231 <property name="text">
208 </widget>232 <string>password_label</string>
209 </item>233 </property>
210 </layout>234 </widget>
211 </item>235 </item>
212 <item>236 <item>
213 <widget class="QCheckBox" name="terms_checkbox">237 <widget class="QLineEdit" name="password_edit">
214 <property name="text">238 <property name="sizePolicy">
215 <string/>239 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
216 </property>240 <horstretch>0</horstretch>
217 </widget>241 <verstretch>0</verstretch>
218 </item>242 </sizepolicy>
219 <item>243 </property>
220 <layout class="QHBoxLayout" name="horizontalLayout_4">244 <property name="minimumSize">
221 <property name="spacing">245 <size>
222 <number>0</number>246 <width>300</width>
223 </property>247 <height>0</height>
224 <item>248 </size>
225 <widget class="QPushButton" name="terms_button">249 </property>
226 <property name="text">250 <property name="maximumSize">
227 <string/>251 <size>
228 </property>252 <width>300</width>
229 </widget>253 <height>16777215</height>
230 </item>254 </size>
231 <item>255 </property>
232 <spacer name="horizontalSpacer_3">256 <property name="font">
233 <property name="orientation">257 <font>
234 <enum>Qt::Horizontal</enum>258 <pointsize>11</pointsize>
235 </property>259 </font>
236 <property name="sizeHint" stdset="0">260 </property>
237 <size>261 <property name="toolTip">
238 <width>40</width>262 <string>Your password must be at least 8 characters long and at least contain one number and one upper later.</string>
239 <height>20</height>263 </property>
240 </size>264 <property name="statusTip">
241 </property>265 <string/>
242 </spacer>266 </property>
243 </item>267 <property name="echoMode">
244 <item>268 <enum>QLineEdit::Password</enum>
245 <widget class="QPushButton" name="set_up_button">269 </property>
246 <property name="enabled">270 <property name="placeholderText">
247 <bool>false</bool>271 <string/>
248 </property>272 </property>
249 <property name="text">273 <property name="formError" stdset="0">
250 <string/>274 <bool>false</bool>
251 </property>275 </property>
252 </widget>276 </widget>
253 </item>277 </item>
254 </layout>278 </layout>
255 </item>279 </item>
256 </layout>280 <item row="7" column="0">
257 </item>281 <layout class="QVBoxLayout" name="verticalLayout">
258 </layout>282 <property name="spacing">
259 </widget>283 <number>3</number>
260 </item>284 </property>
261 <item>285 <item>
286 <widget class="QLabel" name="confirm_password_label">
287 <property name="font">
288 <font>
289 <weight>75</weight>
290 <bold>true</bold>
291 </font>
292 </property>
293 <property name="text">
294 <string>confirm_password_label</string>
295 </property>
296 </widget>
297 </item>
298 <item>
299 <widget class="QLineEdit" name="confirm_password_edit">
300 <property name="sizePolicy">
301 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
302 <horstretch>0</horstretch>
303 <verstretch>0</verstretch>
304 </sizepolicy>
305 </property>
306 <property name="minimumSize">
307 <size>
308 <width>300</width>
309 <height>0</height>
310 </size>
311 </property>
312 <property name="maximumSize">
313 <size>
314 <width>300</width>
315 <height>16777215</height>
316 </size>
317 </property>
318 <property name="font">
319 <font>
320 <pointsize>11</pointsize>
321 </font>
322 </property>
323 <property name="echoMode">
324 <enum>QLineEdit::Password</enum>
325 </property>
326 <property name="placeholderText">
327 <string/>
328 </property>
329 <property name="formError" stdset="0">
330 <bool>false</bool>
331 </property>
332 </widget>
333 </item>
334 </layout>
335 </item>
336 <item row="9" column="0">
337 <layout class="QVBoxLayout" name="verticalLayout">
338 <property name="spacing">
339 <number>3</number>
340 </property>
341 <item>
342 <widget class="QLabel" name="captcha_view">
343 <property name="sizePolicy">
344 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
345 <horstretch>0</horstretch>
346 <verstretch>0</verstretch>
347 </sizepolicy>
348 </property>
349 <property name="minimumSize">
350 <size>
351 <width>300</width>
352 <height>57</height>
353 </size>
354 </property>
355 <property name="maximumSize">
356 <size>
357 <width>300</width>
358 <height>16777215</height>
359 </size>
360 </property>
361 <property name="styleSheet">
362 <string notr="true">background-color: white</string>
363 </property>
364 <property name="frameShape">
365 <enum>QFrame::Box</enum>
366 </property>
367 <property name="text">
368 <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>
369 </property>
370 </widget>
371 </item>
372 <item>
373 <widget class="QLineEdit" name="captcha_solution_edit">
374 <property name="sizePolicy">
375 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
376 <horstretch>0</horstretch>
377 <verstretch>0</verstretch>
378 </sizepolicy>
379 </property>
380 <property name="minimumSize">
381 <size>
382 <width>300</width>
383 <height>0</height>
384 </size>
385 </property>
386 <property name="maximumSize">
387 <size>
388 <width>300</width>
389 <height>16777215</height>
390 </size>
391 </property>
392 <property name="font">
393 <font>
394 <pointsize>11</pointsize>
395 </font>
396 </property>
397 <property name="locale">
398 <locale language="English" country="UnitedStates"/>
399 </property>
400 <property name="inputMask">
401 <string/>
402 </property>
403 <property name="text">
404 <string/>
405 </property>
406 <property name="placeholderText">
407 <string/>
408 </property>
409 <property name="formError" stdset="0">
410 <bool>false</bool>
411 </property>
412 </widget>
413 </item>
414 </layout>
415 </item>
416 <item row="9" column="1">
417 <widget class="QLabel" name="refresh_label">
418 <property name="sizePolicy">
419 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
420 <horstretch>0</horstretch>
421 <verstretch>0</verstretch>
422 </sizepolicy>
423 </property>
424 <property name="minimumSize">
425 <size>
426 <width>220</width>
427 <height>0</height>
428 </size>
429 </property>
430 <property name="maximumSize">
431 <size>
432 <width>220</width>
433 <height>16777215</height>
434 </size>
435 </property>
436 <property name="locale">
437 <locale language="English" country="UnitedStates"/>
438 </property>
439 <property name="text">
440 <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>
441 </property>
442 <property name="wordWrap">
443 <bool>true</bool>
444 </property>
445 <property name="indent">
446 <number>0</number>
447 </property>
448 </widget>
449 </item>
450 <item row="1" column="1">
451 <layout class="QVBoxLayout" name="verticalLayout_7">
452 <property name="spacing">
453 <number>0</number>
454 </property>
455 <property name="leftMargin">
456 <number>0</number>
457 </property>
458 <item>
459 <widget class="QLabel" name="name_assistance">
460 <property name="sizePolicy">
461 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
462 <horstretch>0</horstretch>
463 <verstretch>0</verstretch>
464 </sizepolicy>
465 </property>
466 <property name="minimumSize">
467 <size>
468 <width>220</width>
469 <height>0</height>
470 </size>
471 </property>
472 <property name="maximumSize">
473 <size>
474 <width>220</width>
475 <height>16777215</height>
476 </size>
477 </property>
478 <property name="text">
479 <string>name_assistance</string>
480 </property>
481 <property name="alignment">
482 <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
483 </property>
484 <property name="wordWrap">
485 <bool>true</bool>
486 </property>
487 </widget>
488 </item>
489 </layout>
490 </item>
491 <item row="3" column="1">
492 <layout class="QVBoxLayout" name="verticalLayout_8">
493 <property name="spacing">
494 <number>0</number>
495 </property>
496 <property name="leftMargin">
497 <number>0</number>
498 </property>
499 <item>
500 <widget class="QLabel" name="email_assistance">
501 <property name="sizePolicy">
502 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
503 <horstretch>0</horstretch>
504 <verstretch>0</verstretch>
505 </sizepolicy>
506 </property>
507 <property name="minimumSize">
508 <size>
509 <width>220</width>
510 <height>0</height>
511 </size>
512 </property>
513 <property name="maximumSize">
514 <size>
515 <width>220</width>
516 <height>16777215</height>
517 </size>
518 </property>
519 <property name="text">
520 <string>email_assistance</string>
521 </property>
522 <property name="alignment">
523 <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
524 </property>
525 <property name="wordWrap">
526 <bool>true</bool>
527 </property>
528 </widget>
529 </item>
530 </layout>
531 </item>
532 <item row="4" column="1">
533 <layout class="QVBoxLayout" name="verticalLayout_9">
534 <property name="spacing">
535 <number>0</number>
536 </property>
537 <property name="leftMargin">
538 <number>0</number>
539 </property>
540 <item>
541 <widget class="QLabel" name="confirm_email_assistance">
542 <property name="sizePolicy">
543 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
544 <horstretch>0</horstretch>
545 <verstretch>0</verstretch>
546 </sizepolicy>
547 </property>
548 <property name="minimumSize">
549 <size>
550 <width>220</width>
551 <height>0</height>
552 </size>
553 </property>
554 <property name="maximumSize">
555 <size>
556 <width>220</width>
557 <height>16777215</height>
558 </size>
559 </property>
560 <property name="text">
561 <string>confirm_email_assistance</string>
562 </property>
563 <property name="alignment">
564 <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
565 </property>
566 <property name="wordWrap">
567 <bool>true</bool>
568 </property>
569 <property name="indent">
570 <number>0</number>
571 </property>
572 </widget>
573 </item>
574 </layout>
575 </item>
576 <item row="6" column="1" rowspan="2">
577 <widget class="QLabel" name="password_assistance">
578 <property name="sizePolicy">
579 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
580 <horstretch>0</horstretch>
581 <verstretch>0</verstretch>
582 </sizepolicy>
583 </property>
584 <property name="minimumSize">
585 <size>
586 <width>220</width>
587 <height>0</height>
588 </size>
589 </property>
590 <property name="maximumSize">
591 <size>
592 <width>220</width>
593 <height>16777215</height>
594 </size>
595 </property>
596 <property name="text">
597 <string>password_assistance</string>
598 </property>
599 <property name="wordWrap">
600 <bool>true</bool>
601 </property>
602 <property name="indent">
603 <number>17</number>
604 </property>
605 </widget>
606 </item>
607 <item row="2" column="1">
608 <spacer name="verticalSpacer">
609 <property name="orientation">
610 <enum>Qt::Vertical</enum>
611 </property>
612 <property name="sizeType">
613 <enum>QSizePolicy::Fixed</enum>
614 </property>
615 <property name="sizeHint" stdset="0">
616 <size>
617 <width>20</width>
618 <height>15</height>
619 </size>
620 </property>
621 </spacer>
622 </item>
623 <item row="5" column="1">
262 <spacer name="verticalSpacer_2">624 <spacer name="verticalSpacer_2">
263 <property name="orientation">625 <property name="orientation">
264 <enum>Qt::Vertical</enum>626 <enum>Qt::Vertical</enum>
265 </property>627 </property>
266 <property name="sizeHint" stdset="0">628 <property name="sizeType">
267 <size>629 <enum>QSizePolicy::Fixed</enum>
268 <width>20</width>630 </property>
269 <height>40</height>631 <property name="sizeHint" stdset="0">
270 </size>632 <size>
271 </property>633 <width>20</width>
272 </spacer>634 <height>15</height>
273 </item>635 </size>
636 </property>
637 </spacer>
638 </item>
639 <item row="8" column="1">
640 <spacer name="verticalSpacer_3">
641 <property name="orientation">
642 <enum>Qt::Vertical</enum>
643 </property>
644 <property name="sizeType">
645 <enum>QSizePolicy::Fixed</enum>
646 </property>
647 <property name="sizeHint" stdset="0">
648 <size>
649 <width>20</width>
650 <height>15</height>
651 </size>
652 </property>
653 </spacer>
654 </item>
655 </layout>
656 </item>
657 <item>
658 <layout class="QHBoxLayout" name="hlayout_check">
659 <property name="spacing">
660 <number>0</number>
661 </property>
274 </layout>662 </layout>
275 </item>663 </item>
276 </layout>664 </layout>
277 </widget>665 </widget>
278 <resources/>
279 <connections/>666 <connections/>
280</ui>667</ui>
281668
=== modified file 'run-tests'
--- run-tests 2011-12-09 14:07:38 +0000
+++ run-tests 2012-02-14 22:04:20 +0000
@@ -18,16 +18,10 @@
1818
19QT_TESTS_PATH=ubuntu_sso/qt/tests19QT_TESTS_PATH=ubuntu_sso/qt/tests
20GTK_TESTS_PATH=ubuntu_sso/gtk/tests20GTK_TESTS_PATH=ubuntu_sso/gtk/tests
21WINDOWS_TESTS=test_windows.py
2122
22set -e23set -e
2324
24if [ "$1" == "-qt" ]; then
25 USE_QT=1
26 shift
27else
28 USE_QT=0
29fi
30
31if [ $# -ne 0 ]; then25if [ $# -ne 0 ]; then
32 # run specific module given by the caller26 # run specific module given by the caller
33 MODULE="$@"27 MODULE="$@"
@@ -37,24 +31,34 @@
37fi31fi
3832
39style_check() {33style_check() {
40 ./setup.py clean34 u1lint --ignore ubuntu_sso/qt/ui
41 u1lint
42 if [ -x `which pep8` ]; then35 if [ -x `which pep8` ]; then
43 pep8 --repeat .36 pep8 --exclude '.svn,CVS,.bzr,.hg,.git,*_ui.py,*_rc.py' --repeat . bin/*
44 else37 else
45 echo "Please install the 'pep8' package."38 echo "Please install the 'pep8' package."
46 fi39 fi
47}40}
48
49unset GTK_MODULES41unset GTK_MODULES
5042
51echo "Running test suite for ""$MODULE"43XVFB_CMDLINE=""
52if [ "$USE_QT" -eq 0 ]; then44XVFB=$(which xvfb-run)
53 `which xvfb-run` u1trial -p "$QT_TESTS_PATH" -i "test_windows.py" "$MODULE"45if [ $XVFB ]; then
54else46 XVFB_CMDLINE="$XVFB -a"
55 ./setup.py build
56 `which xvfb-run` u1trial -p "$GTK_TESTS_PATH" -i "test_windows.py" --reactor=qt4 --gui "$MODULE"
57fi47fi
48
49echo "*** Running GTK test suite for ""$MODULE"" ***"
50$XVFB_CMDLINE u1trial --reactor=gi --gui -p "$QT_TESTS_PATH" -i "test_windows.py" "$MODULE"
51rm -rf _trial_temp
52
53# hack to avoid:
54# g_dbus_connection_real_closed: Remote peer vanished with error: Underlying
55# GIOStream returned 0 bytes on an async read (g-io-error-quark, 0). Exiting.
56sleep 3
57
58echo "*** Running QT test suite for ""$MODULE"" ***"
59./setup.py build
60USE_QT_MAINLOOP=True $XVFB_CMDLINE u1trial --reactor=qt4 --gui -p "$GTK_TESTS_PATH" -i "test_windows.py" "$MODULE"
61rm -rf _trial_temp
62rm -rf build
63
58style_check64style_check
59rm -rf _trial_temp
60rm -rf build
6165
=== modified file 'setup.py'
--- setup.py 2012-02-02 13:37:55 +0000
+++ setup.py 2012-02-14 22:04:20 +0000
@@ -1,11 +1,7 @@
1#!/usr/bin/env python1#!/usr/bin/env python
2# setup.py - Build system for Ubuntu SSO Client package2# setup.py - Build system for Ubuntu SSO Client package
3#3#
4# Authors: Natalia B. Bidart <natalia.bidart@canonical.com>4# Copyright 2010-2012 Canonical Ltd.
5# Manuel de la Pena <manuel@canonical.com>
6# Alejandro J. Cura <alecu@canonical.com>
7#
8# Copyright 2010-2011 Canonical Ltd.
9#5#
10# This program is free software: you can redistribute it and/or modify it6# This program is free software: you can redistribute it and/or modify it
11# under the terms of the GNU General Public License version 3, as published7# under the terms of the GNU General Public License version 3, as published
@@ -40,15 +36,16 @@
4036
41POT_FILE = 'po/ubuntu-sso-client.pot'37POT_FILE = 'po/ubuntu-sso-client.pot'
42SERVICE_FILE = 'data/com.ubuntu.sso.service'38SERVICE_FILE = 'data/com.ubuntu.sso.service'
39CONSTANTS = 'ubuntu_sso/constants.py'
4340
44CLEANFILES = [SERVICE_FILE, POT_FILE, 'MANIFEST']41CLEANFILES = [SERVICE_FILE, POT_FILE, CONSTANTS, 'MANIFEST']
45QT_UI_DIR = os.path.join('ubuntu_sso', 'qt')42QT_UI_DIR = os.path.join('ubuntu_sso', 'qt', 'ui')
4643
4744
48def replace_prefix(prefix):45def replace_prefix(prefix):
49 """Replace every '@prefix@' with prefix within 'filename' content."""46 """Replace every '@prefix@' with prefix within 'filename' content."""
50 # replace .service file47 # replace .service file, DATA_DIR constant
51 for filename in (SERVICE_FILE,):48 for filename in (SERVICE_FILE, CONSTANTS):
52 with open(filename + '.in') as in_file:49 with open(filename + '.in') as in_file:
53 content = in_file.read()50 content = in_file.read()
54 with open(filename, 'w') as out_file:51 with open(filename, 'w') as out_file:
@@ -112,7 +109,8 @@
112 path = os.getenv('PATH')109 path = os.getenv('PATH')
113 os.putenv('PATH', path + os.path.pathsep + os.path.join(110 os.putenv('PATH', path + os.path.pathsep + os.path.join(
114 os.path.dirname(PyQt4.__file__), 'bin'))111 os.path.dirname(PyQt4.__file__), 'bin'))
115 if os.system('pyrcc4 "%s" -o "%s"' % (qrc_file, py_file)) > 0:112 if os.system('pyrcc4 -no-compress "%s" -o "%s"' %
113 (qrc_file, py_file)) > 0:
116 self.warn('Unable to generate python module {py_file}'114 self.warn('Unable to generate python module {py_file}'
117 ' for resource file {qrc_file}'.format(115 ' for resource file {qrc_file}'.format(
118 py_file=py_file, qrc_file=qrc_file))116 py_file=py_file, qrc_file=qrc_file))
@@ -313,6 +311,14 @@
313}311}
314312
315313
314sso_executables = [
315 'bin/ubuntu-sso-login',
316 'bin/ubuntu-sso-login-gtk',
317 'bin/ubuntu-sso-login-qt',
318 'bin/ubuntu-sso-proxy-creds-qt',
319]
320
321
316class dummy_build_i18n(distutils.cmd.Command):322class dummy_build_i18n(distutils.cmd.Command):
317323
318 """Dummy for windows."""324 """Dummy for windows."""
@@ -326,6 +332,7 @@
326 def run(self, *args):332 def run(self, *args):
327 """Dummy."""333 """Dummy."""
328334
335
329if sys.platform == 'win32':336if sys.platform == 'win32':
330 cmdclass['build_i18n'] = dummy_build_i18n337 cmdclass['build_i18n'] = dummy_build_i18n
331338
@@ -349,7 +356,7 @@
349 },356 },
350 },357 },
351 # add the console script so that py2exe compiles it358 # add the console script so that py2exe compiles it
352 'console': ['bin/ubuntu-sso-login'],359 'console': sso_executables,
353 'zipfile': None,360 'zipfile': None,
354 }361 }
355 return _data_files, _extra362 return _data_files, _extra
@@ -358,10 +365,8 @@
358 data_files, extra = setup_windows()365 data_files, extra = setup_windows()
359else:366else:
360 data_files = [367 data_files = [
361 ('lib/ubuntu-sso-client', ['bin/ubuntu-sso-login']),368 ('lib/ubuntu-sso-client', sso_executables),
362 ('lib/ubuntu-sso-client', ['bin/ubuntu-sso-login-gtk']),
363 ('share/dbus-1/services', ['data/com.ubuntu.sso.service']),369 ('share/dbus-1/services', ['data/com.ubuntu.sso.service']),
364 ('share/ubuntu-sso-client/data/gtk', ['data/gtk/ui.glade']),
365 ]370 ]
366 extra = {}371 extra = {}
367372
@@ -379,14 +384,24 @@
379 data_files=data_files,384 data_files=data_files,
380 packages=[385 packages=[
381 'ubuntu_sso',386 'ubuntu_sso',
387 'ubuntu_sso.tests',
382 'ubuntu_sso.gtk',388 'ubuntu_sso.gtk',
383 'ubuntu_sso.keyring',389 'ubuntu_sso.keyring',
390 'ubuntu_sso.keyring.tests',
384 'ubuntu_sso.main',391 'ubuntu_sso.main',
392 'ubuntu_sso.main.tests',
385 'ubuntu_sso.networkstate',393 'ubuntu_sso.networkstate',
394 'ubuntu_sso.networkstate.tests',
386 'ubuntu_sso.qt',395 'ubuntu_sso.qt',
396 'ubuntu_sso.qt.ui',
387 'ubuntu_sso.utils',397 'ubuntu_sso.utils',
398 'ubuntu_sso.utils.tests',
399 'ubuntu_sso.utils.runner',
400 'ubuntu_sso.utils.runner.tests',
388 'ubuntu_sso.utils.webclient',401 'ubuntu_sso.utils.webclient',
402 'ubuntu_sso.utils.webclient.tests',
389 'ubuntu_sso.xdg_base_directory',403 'ubuntu_sso.xdg_base_directory',
404 'ubuntu_sso.xdg_base_directory.tests',
390 ],405 ],
391 cmdclass=cmdclass,406 cmdclass=cmdclass,
392 **extra)407 **extra)
393408
=== modified file 'ubuntu_sso/__init__.py'
--- ubuntu_sso/__init__.py 2010-10-07 21:09:01 +0000
+++ ubuntu_sso/__init__.py 2012-02-14 22:04:20 +0000
@@ -15,17 +15,21 @@
15# with this program. If not, see <http://www.gnu.org/licenses/>.15# with this program. If not, see <http://www.gnu.org/licenses/>.
16"""Ubuntu Single Sign On client code."""16"""Ubuntu Single Sign On client code."""
1717
18# constants18# DBus constants
19DBUS_BUS_NAME = "com.ubuntu.sso"19DBUS_BUS_NAME = "com.ubuntu.sso"
20DBUS_PATH = "/sso" # deprecated!20
21DBUS_CRED_PATH = "/credentials" # deprecated!
22DBUS_ACCOUNT_PATH = "/com/ubuntu/sso/accounts"21DBUS_ACCOUNT_PATH = "/com/ubuntu/sso/accounts"
23
24DBUS_IFACE_AUTH_NAME = "com.ubuntu.sso"
25DBUS_IFACE_USER_NAME = "com.ubuntu.sso.UserManagement"22DBUS_IFACE_USER_NAME = "com.ubuntu.sso.UserManagement"
26DBUS_IFACE_CRED_NAME = "com.ubuntu.sso.ApplicationCredentials"
2723
28DBUS_CREDENTIALS_PATH = "/com/ubuntu/sso/credentials"24DBUS_CREDENTIALS_PATH = "/com/ubuntu/sso/credentials"
29DBUS_CREDENTIALS_IFACE = "com.ubuntu.sso.CredentialsManagement"25DBUS_CREDENTIALS_IFACE = "com.ubuntu.sso.CredentialsManagement"
3026
31NO_OP = lambda *args, **kwargs: None27NO_OP = lambda *args, **kwargs: None
28
29# return codes for UIs
30USER_SUCCESS = 0
31USER_CANCELLATION = 10
32
33# available UIs
34UI_EXECUTABLE_GTK = 'ubuntu-sso-login-gtk'
35UI_EXECUTABLE_QT = 'ubuntu-sso-login-qt'
3236
=== modified file 'ubuntu_sso/account.py'
--- ubuntu_sso/account.py 2011-12-15 20:52:32 +0000
+++ ubuntu_sso/account.py 2012-02-14 22:04:20 +0000
@@ -16,27 +16,27 @@
16#16#
17# You should have received a copy of the GNU General Public License along17# You should have received a copy of the GNU General Public License along
18# with this program. If not, see <http://www.gnu.org/licenses/>.18# with this program. If not, see <http://www.gnu.org/licenses/>.
19"""Single Sign On account management."""19"""Single Sign On account management.
20
21All the methods in Account expect unicode as parameters.
22
23"""
2024
21import os25import os
22import re26import re
23import urllib2
2427
25# Unable to import 'lazr.restfulclient.*'
26# pylint: disable=F0401
27from lazr.restfulclient.authorize import BasicHttpAuthorizer
28from lazr.restfulclient.authorize.oauth import OAuthAuthorizer28from lazr.restfulclient.authorize.oauth import OAuthAuthorizer
29from lazr.restfulclient.errors import HTTPError
30from lazr.restfulclient.resource import ServiceRoot
31# pylint: enable=F0401
32from oauth import oauth29from oauth import oauth
30from twisted.internet import defer
3331
34from ubuntu_sso.logger import setup_logging32from ubuntu_sso.logger import setup_logging
35from ubuntu_sso.utils import timestamp_checker33from ubuntu_sso.utils import webclient
34from ubuntu_sso.utils.webclient import restful
35from ubuntu_sso.utils.webclient.common import WebClientError
3636
3737
38logger = setup_logging("ubuntu_sso.account")38logger = setup_logging("ubuntu_sso.account")
39SERVICE_URL = "https://login.ubuntu.com/api/1.0"39SERVICE_URL = u"https://login.ubuntu.com/api/1.0/"
40SSO_STATUS_OK = 'ok'40SSO_STATUS_OK = 'ok'
41SSO_STATUS_ERROR = 'error'41SSO_STATUS_ERROR = 'error'
4242
@@ -102,8 +102,9 @@
102 self.service_url = service_url102 self.service_url = service_url
103 else:103 else:
104 self.service_url = os.environ.get('USSOC_SERVICE_URL', SERVICE_URL)104 self.service_url = os.environ.get('USSOC_SERVICE_URL', SERVICE_URL)
105 logger.info('Created a new SSO access layer for service url %r',105 logger.info('Creating a new SSO access layer for service url %r',
106 self.service_url)106 self.service_url)
107 assert self.service_url.endswith("/")
107108
108 def _valid_email(self, email):109 def _valid_email(self, email):
109 """Validate the given email."""110 """Validate the given email."""
@@ -127,46 +128,57 @@
127 result[key] = "\n".join(val)128 result[key] = "\n".join(val)
128 return result129 return result
129130
131 @defer.inlineCallbacks
130 def generate_captcha(self, filename):132 def generate_captcha(self, filename):
131 """Generate a captcha using the SSO service."""133 """Generate a captcha using the SSO service."""
132 logger.debug('generate_captcha: requesting captcha, filename: %r',134 logger.debug('generate_captcha: requesting captcha, filename: %r',
133 filename)135 filename)
134 sso_service = ServiceRoot(None, self.service_url)136 restful_client = restful.RestfulClient(self.service_url)
135 captcha = sso_service.captchas.new()137 try:
138 captcha = yield restful_client.restcall(u"captchas.new")
139 finally:
140 restful_client.shutdown()
136141
137 # download captcha and save to 'filename'142 # download captcha and save to 'filename'
138 logger.debug('generate_captcha: server answered: %r', captcha)143 logger.debug('generate_captcha: server answered: %r', captcha)
144 wc = webclient.webclient_factory()
139 try:145 try:
140 res = urllib2.urlopen(captcha['image_url'])146 response = yield wc.request(captcha['image_url'])
141 with open(filename, 'wb') as f:147 with open(filename, 'wb') as f:
142 f.write(res.read())148 f.write(response.content)
143 except:149 except:
144 msg = 'generate_captcha crashed while downloading the image.'150 msg = 'generate_captcha crashed while downloading the image.'
145 logger.exception(msg)151 logger.exception(msg)
146 raise152 raise
147153 finally:
148 return captcha['captcha_id']154 wc.shutdown()
149155
156 defer.returnValue(captcha['captcha_id'])
157
158 @defer.inlineCallbacks
150 def register_user(self, email, password, displayname,159 def register_user(self, email, password, displayname,
151 captcha_id, captcha_solution):160 captcha_id, captcha_solution):
152 """Register a new user with 'email' and 'password'."""161 """Register a new user with 'email' and 'password'."""
153 logger.debug('register_user: email: %r password: <hidden>, '162 logger.debug('register_user: email: %r password: <hidden>, '
154 'displayname: %r, captcha_id: %r, captcha_solution: %r',163 'displayname: %r, captcha_id: %r, captcha_solution: %r',
155 email, displayname, captcha_id, captcha_solution)164 email, displayname, captcha_id, captcha_solution)
156 sso_service = ServiceRoot(None, self.service_url)165 restful_client = restful.RestfulClient(self.service_url)
157 if not self._valid_email(email):166 try:
158 logger.error('register_user: InvalidEmailError for email: %r',167 if not self._valid_email(email):
159 email)168 logger.error('register_user: InvalidEmailError for email: %r',
160 raise InvalidEmailError()169 email)
161 if not self._valid_password(password):170 raise InvalidEmailError()
162 logger.error('register_user: InvalidPasswordError')171 if not self._valid_password(password):
163 raise InvalidPasswordError()172 logger.error('register_user: InvalidPasswordError')
173 raise InvalidPasswordError()
164174
165 result = sso_service.registrations.register(175 result = yield restful_client.restcall(u"registration.register",
166 email=email, password=password,176 email=email, password=password,
167 displayname=displayname,177 displayname=displayname,
168 captcha_id=captcha_id,178 captcha_id=captcha_id,
169 captcha_solution=captcha_solution)179 captcha_solution=captcha_solution)
180 finally:
181 restful_client.shutdown()
170 logger.info('register_user: email: %r result: %r', email, result)182 logger.info('register_user: email: %r result: %r', email, result)
171183
172 if result['status'].lower() == SSO_STATUS_ERROR:184 if result['status'].lower() == SSO_STATUS_ERROR:
@@ -175,87 +187,91 @@
175 elif result['status'].lower() != SSO_STATUS_OK:187 elif result['status'].lower() != SSO_STATUS_OK:
176 raise RegistrationError('Received unknown status: %s' % result)188 raise RegistrationError('Received unknown status: %s' % result)
177 else:189 else:
178 return email190 defer.returnValue(email)
179191
192 @defer.inlineCallbacks
180 def login(self, email, password, token_name):193 def login(self, email, password, token_name):
181 """Login a user with 'email' and 'password'."""194 """Login a user with 'email' and 'password'."""
182 logger.debug('login: email: %r password: <hidden>, token_name: %r',195 logger.debug('login: email: %r password: <hidden>, token_name: %r',
183 email, token_name)196 email, token_name)
184 basic = BasicHttpAuthorizer(email, password)197 restful_client = restful.RestfulClient(self.service_url,
185 sso_service = ServiceRoot(basic, self.service_url)198 username=email,
186 service = sso_service.authentications.authenticate199 password=password)
187
188 try:200 try:
189 credentials = service(token_name=token_name)201 credentials = yield restful_client.restcall(
190 except HTTPError:202 u"authentications.authenticate",
203 token_name=token_name)
204 except WebClientError:
191 logger.exception('login failed with:')205 logger.exception('login failed with:')
192 raise AuthenticationError()206 raise AuthenticationError()
207 finally:
208 restful_client.shutdown()
193209
194 logger.debug('login: authentication successful! consumer_key: %r, ' \210 logger.debug('login: authentication successful! consumer_key: %r, ' \
195 'token_name: %r', credentials['consumer_key'], token_name)211 'token_name: %r', credentials['consumer_key'], token_name)
196 return credentials212 defer.returnValue(credentials)
197213
198 def is_validated(self, token, sso_service=None):214 @defer.inlineCallbacks
215 def is_validated(self, token):
199 """Return if user with 'email' and 'password' is validated."""216 """Return if user with 'email' and 'password' is validated."""
200 logger.debug('is_validated: requesting accounts.me() info.')217 logger.debug('is_validated: requesting accounts.me() info.')
201 if sso_service is None:218 restful_client = restful.RestfulClient(self.service_url,
202 oauth_token = oauth.OAuthToken(token['token'],219 oauth_credentials=token)
203 token['token_secret'])220 try:
204 authorizer = TimestampedAuthorizer(221 me_info = yield restful_client.restcall(u"accounts.me")
205 timestamp_checker.get_faithful_time,222 finally:
206 token['consumer_key'],223 restful_client.shutdown()
207 token['consumer_secret'],
208 oauth_token)
209 sso_service = ServiceRoot(authorizer, self.service_url)
210
211 me_info = sso_service.accounts.me()
212 key = 'preferred_email'224 key = 'preferred_email'
213 result = key in me_info and me_info[key] != None225 result = key in me_info and me_info[key] != None
214226
215 logger.info('is_validated: consumer_key: %r, result: %r.',227 logger.info('is_validated: consumer_key: %r, result: %r.',
216 token['consumer_key'], result)228 token['consumer_key'], result)
217 return result229 defer.returnValue(result)
218230
231 @defer.inlineCallbacks
219 def validate_email(self, email, password, email_token, token_name):232 def validate_email(self, email, password, email_token, token_name):
220 """Validate an email token for user with 'email' and 'password'."""233 """Validate an email token for user with 'email' and 'password'."""
221 logger.debug('validate_email: email: %r password: <hidden>, '234 logger.debug('validate_email: email: %r password: <hidden>, '
222 'email_token: %r, token_name: %r.',235 'email_token: %r, token_name: %r.',
223 email, email_token, token_name)236 email, email_token, token_name)
224 token = self.login(email=email, password=password,237 credentials = yield self.login(email=email, password=password,
225 token_name=token_name)238 token_name=token_name)
226239 restful_client = restful.RestfulClient(self.service_url,
227 oauth_token = oauth.OAuthToken(token['token'], token['token_secret'])240 oauth_credentials=credentials)
228 authorizer = TimestampedAuthorizer(timestamp_checker.get_faithful_time,241 try:
229 token['consumer_key'],242 result = yield restful_client.restcall(u"accounts.validate_email",
230 token['consumer_secret'],243 email_token=email_token)
231 oauth_token)244 finally:
232 sso_service = ServiceRoot(authorizer, self.service_url)245 restful_client.shutdown()
233 result = sso_service.accounts.validate_email(email_token=email_token)
234 logger.info('validate_email: email: %r result: %r', email, result)246 logger.info('validate_email: email: %r result: %r', email, result)
235 if 'errors' in result:247 if 'errors' in result:
236 errorsdict = self._format_webservice_errors(result['errors'])248 errorsdict = self._format_webservice_errors(result['errors'])
237 raise EmailTokenError(errorsdict)249 raise EmailTokenError(errorsdict)
238 elif 'email' in result:250 elif 'email' in result:
239 return token251 defer.returnValue(credentials)
240 else:252 else:
241 raise EmailTokenError('Received invalid reply: %s' % result)253 raise EmailTokenError('Received invalid reply: %s' % result)
242254
255 @defer.inlineCallbacks
243 def request_password_reset_token(self, email):256 def request_password_reset_token(self, email):
244 """Request a token to reset the password for the account 'email'."""257 """Request a token to reset the password for the account 'email'."""
245 sso_service = ServiceRoot(None, self.service_url)258 restful_client = restful.RestfulClient(self.service_url)
246 service = sso_service.registrations.request_password_reset_token
247 try:259 try:
248 result = service(email=email)260 operation = u"registration.request_password_reset_token"
249 except HTTPError, e:261 result = yield restful_client.restcall(operation, email=email)
262 except WebClientError, e:
250 logger.exception('request_password_reset_token failed with:')263 logger.exception('request_password_reset_token failed with:')
251 raise ResetPasswordTokenError(e.content.split('\n')[0])264 raise ResetPasswordTokenError(e[1].split('\n')[0])
265 finally:
266 restful_client.shutdown()
252267
253 if result['status'].lower() == SSO_STATUS_OK:268 if result['status'].lower() == SSO_STATUS_OK:
254 return email269 defer.returnValue(email)
255 else:270 else:
256 raise ResetPasswordTokenError('Received invalid reply: %s' %271 raise ResetPasswordTokenError('Received invalid reply: %s' %
257 result)272 result)
258273
274 @defer.inlineCallbacks
259 def set_new_password(self, email, token, new_password):275 def set_new_password(self, email, token, new_password):
260 """Set a new password for the account 'email' to be 'new_password'.276 """Set a new password for the account 'email' to be 'new_password'.
261277
@@ -263,16 +279,19 @@
263 'request_password_reset_token'.279 'request_password_reset_token'.
264280
265 """281 """
266 sso_service = ServiceRoot(None, self.service_url)282 restful_client = restful.RestfulClient(self.service_url)
267 service = sso_service.registrations.set_new_password
268 try:283 try:
269 result = service(email=email, token=token,284 result = yield restful_client.restcall(
270 new_password=new_password)285 u"registration.set_new_password",
271 except HTTPError, e:286 email=email, token=token,
287 new_password=new_password)
288 except WebClientError, e:
272 logger.exception('set_new_password failed with:')289 logger.exception('set_new_password failed with:')
273 raise NewPasswordError(e.content.split('\n')[0])290 raise NewPasswordError(e[1].split('\n')[0])
291 finally:
292 restful_client.shutdown()
274293
275 if result['status'].lower() == SSO_STATUS_OK:294 if result['status'].lower() == SSO_STATUS_OK:
276 return email295 defer.returnValue(email)
277 else:296 else:
278 raise NewPasswordError('Received invalid reply: %s' % result)297 raise NewPasswordError('Received invalid reply: %s' % result)
279298
=== added file 'ubuntu_sso/constants.py.in'
--- ubuntu_sso/constants.py.in 1970-01-01 00:00:00 +0000
+++ ubuntu_sso/constants.py.in 2012-02-14 22:04:20 +0000
@@ -0,0 +1,28 @@
1# -*- coding: utf-8 -*-
2#
3# Copyright 2012 Canonical Ltd.
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program. If not, see <http://www.gnu.org/licenses/>.
16
17"""Some generated constants.
18
19DO NO EDIT! This is a generated file. It will be built at installation time.
20
21"""
22
23import os
24
25
26PROJECT_NAME = 'ubuntu-sso-client'
27PROJECT_DIR = os.path.join('@prefix@', 'share', PROJECT_NAME)
28BIN_DIR = os.path.join('@prefix@', 'lib', PROJECT_NAME)
029
=== modified file 'ubuntu_sso/credentials.py'
--- ubuntu_sso/credentials.py 2012-01-17 15:09:12 +0000
+++ ubuntu_sso/credentials.py 2012-02-14 22:04:20 +0000
@@ -1,9 +1,6 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2
3# Author: Natalia Bidart <natalia.bidart@canonical.com>
4# Author: Alejandro J. Cura <alecu@canonical.com>
5#2#
6# Copyright 2010 Canonical Ltd.3# Copyright 2010-2012 Canonical Ltd.
7#4#
8# This program is free software: you can redistribute it and/or modify it5# This program is free software: you can redistribute it and/or modify it
9# under the terms of the GNU General Public License version 3, as published6# under the terms of the GNU General Public License version 3, as published
@@ -26,28 +23,24 @@
26 * register23 * register
27 * login24 * login
2825
29The first three return a Deferred that will be fired when the operation was26All the methods return a Deferred that will be fired when the operation was
30completed.27completed.
3128
32The second two use the 'success_cb', 'error_cb' and 'denial_cb' to signal the
33caller when the credentials were retrieved successfully, when there was an
34error or when the user denied the access to the application, respectively.
35
36For details, please read the Credentials class documentation.29For details, please read the Credentials class documentation.
3730
38"""31"""
3932
40import sys33import os
41import traceback
42import urllib2
4334
44from functools import wraps35from functools import wraps
4536
46from twisted.internet import defer37from twisted.internet import defer
4738
48from ubuntu_sso import NO_OP, utils39from ubuntu_sso import UI_EXECUTABLE_GTK, USER_CANCELLATION, USER_SUCCESS
49from ubuntu_sso.keyring import Keyring40from ubuntu_sso.keyring import Keyring
50from ubuntu_sso.logger import setup_logging41from ubuntu_sso.logger import setup_logging
42from ubuntu_sso.utils import get_bin_dir, runner
43
5144
52logger = setup_logging('ubuntu_sso.credentials')45logger = setup_logging('ubuntu_sso.credentials')
5346
@@ -57,44 +50,20 @@
57HELP_TEXT_KEY = 'help_text'50HELP_TEXT_KEY = 'help_text'
58WINDOW_ID_KEY = 'window_id'51WINDOW_ID_KEY = 'window_id'
59PING_URL_KEY = 'ping_url'52PING_URL_KEY = 'ping_url'
60UI_MODULE_KEY = 'ui_module'53POLICY_URL_KEY = 'policy_url'
61UI_CLASS_KEY = 'ui_class'54UI_EXECUTABLE_KEY = 'ui_executable'
62SUCCESS_CB_KEY = 'success_cb'55
63ERROR_CB_KEY = 'error_cb'56
64DENIAL_CB_KEY = 'denial_cb'57class CredentialsError(Exception):
65ERROR_KEY = 'error_message'58 """Generic credentials error."""
66ERROR_DETAIL_KEY = 'detailed_error'59
6760
6861class UserCancellationError(CredentialsError):
69def handle_exceptions(msg):62 """The user cancelled the process of authentication."""
70 """Handle exceptions using 'msg' as error message."""63
7164
72 def middle(f):65class UserNotValidatedError(CredentialsError):
73 """Decorate 'f' to catch all errors."""66 """The user is not validated."""
74
75 @wraps(f)
76 def inner(self, *a, **kw):
77 """Call 'f' within a try-except block.
78
79 If any exception occurs, self.error_cb is called and the exception
80 is logged.
81 """
82 result = None
83 try:
84 result = f(self, *a, **kw)
85 except: # pylint: disable=W0702
86 logger.exception('%s (app_name: %s): %s.',
87 f.__name__, self.app_name, msg)
88 logger.error('%s (app_name: %s): Calling error_cb at %r.',
89 f.__name__, self.app_name, self.error_cb)
90 error_dict = {ERROR_KEY: msg,
91 ERROR_DETAIL_KEY: traceback.format_exc()}
92 self.error_cb(error_dict)
93 return result
94
95 return inner
96
97 return middle
9867
9968
100def handle_failures(msg):69def handle_failures(msg):
@@ -108,20 +77,17 @@
108 def inner(self, *a, **kw):77 def inner(self, *a, **kw):
109 """Call 'f' within a try-except block.78 """Call 'f' within a try-except block.
11079
111 If any exception occurs, self.error_cb is called and the exception80 If any exception occurs, the exception is logged and re-raised.
112 is logged.81
113 """82 """
114 result = None83 result = None
115 try:84 try:
116 result = yield f(self, *a, **kw)85 result = yield f(self, *a, **kw)
117 except Exception: # pylint: disable=W070386 except:
118 logger.exception('%s (app_name: %s): %s.',87 logger.exception('%s (app_name: %s): %s.',
119 f.__name__, self.app_name, msg)88 f.__name__, self.app_name, msg)
120 logger.error('%s (app_name: %s): Calling error_cb at %r.',89 raise
121 f.__name__, self.app_name, self.error_cb)90
122 error_dict = {ERROR_KEY: msg,
123 ERROR_DETAIL_KEY: traceback.format_exc()}
124 self.error_cb(error_dict)
125 defer.returnValue(result)91 defer.returnValue(result)
12692
127 return inner93 return inner
@@ -133,14 +99,13 @@
133 """Credentials management gateway."""99 """Credentials management gateway."""
134100
135 def __init__(self, app_name, tc_url=None, help_text='',101 def __init__(self, app_name, tc_url=None, help_text='',
136 window_id=0, ping_url=None,102 window_id=0, ping_url=None, policy_url=None,
137 ui_module='ubuntu_sso.gtk.gui', ui_class='UbuntuSSOClientGUI',103 ui_executable=UI_EXECUTABLE_GTK):
138 success_cb=NO_OP, error_cb=NO_OP, denial_cb=NO_OP):
139 """Return a Credentials management object.104 """Return a Credentials management object.
140105
141 'app_name' is the application name to be displayed in the GUI.106 'app_name' is the application name to be displayed in the GUI.
142107
143 'tc_url' is the URL pointing to Terms & Conditions. If None, no108 'tc_url' is the url pointing to Terms & Conditions. If None, no
144 TOS agreement will be displayed.109 TOS agreement will be displayed.
145110
146 'help_text' is an explanatory text for the end-users, will be shown111 'help_text' is an explanatory text for the end-users, will be shown
@@ -152,9 +117,11 @@
152 'ping_url' is the url that will be pinged when a user registers/logins117 'ping_url' is the url that will be pinged when a user registers/logins
153 successfully. The user email will be attached to 'ping_url'.118 successfully. The user email will be attached to 'ping_url'.
154119
155 'success_cb' will be called when the credentials were retrieved120 'policy_url' is the url pointing to the privacy policy. If None, no
156 successfully. Two params will be passed: the app_name and the121 privacy policy agreement will be displayed.
157 credentials per se. The credentials is a dictionary of the form:122
123 When the credentials are retrieved successfully, a dictionary like the
124 one below is returned:
158125
159 {'token': <value>,126 {'token': <value>,
160 'token_secret': <value>,127 'token_secret': <value>,
@@ -162,106 +129,44 @@
162 'consumer_secret': <value>,129 'consumer_secret': <value>,
163 'name': <the token name, matches "[app_name] @ [host name]">}130 'name': <the token name, matches "[app_name] @ [host name]">}
164131
165 'error_cb' will be called when the credentials retrieval failed. Two
166 params will be passed: the app_name, and an error dict with 2 keys:
167 the error message (user friendly, not translatable so far), and
168 the detailed error (usually the traceback).
169
170 'denial_cb' will be called when the user denied the credentials to the
171 caller. A single param is passed: the app_name.
172
173 """132 """
174 self.app_name = app_name133 self.app_name = app_name
175 self.help_text = help_text134 self.help_text = help_text
176 self.window_id = window_id135 self.window_id = window_id
177 self.ping_url = ping_url136 self.ping_url = ping_url
178 self.tc_url = tc_url137 self.tc_url = tc_url
179 self.ui_module = ui_module138 self.policy_url = policy_url
180 self.ui_class = ui_class139 self.ui_executable = ui_executable
181 self._success_cb = success_cb
182 self._error_cb = error_cb
183 self.denial_cb = denial_cb
184 self.inner = None # will hold the GUI or SSOLoginRoot instance
185140
186 @handle_failures(msg='Problem while retrieving credentials')
187 @defer.inlineCallbacks141 @defer.inlineCallbacks
188 def _login_success_cb(self, app_name, email):
189 """Store credentials when the login/registration succeeded.
190
191 Also, open self.ping_url/email to notify about this new token. If any
192 error occur, self.error_cb is called. Otherwise, self.success_cb is
193 called.
194
195 Return 0 on success, and a non-zero value (or None) on error.
196
197 """
198 logger.info('Login/registration was successful for app %r, email %r',
199 app_name, email)
200 creds = yield self.find_credentials()
201 if creds is not None:
202 assert len(creds) > 0, 'Creds are empty! This should not happen'
203 # ping a server with the credentials if we were requested to
204 if self.ping_url is not None:
205 status = yield self._ping_url(app_name, email, creds)
206 if status is None:
207 yield self.clear_credentials()
208 return
209
210 self.success_cb(creds)
211 defer.returnValue(0)
212
213 def _auth_denial_cb(self, app_name):
214 """The user decided not to allow the registration or login."""
215 logger.warning('Login/registration was denied to app %r', app_name)
216 self.denial_cb(app_name)
217
218 @handle_failures(msg='Problem opening the ping_url')
219 def _ping_url(self, app_name, email, credentials):
220 """Ping the self.ping_url with the email attached.
221
222 Sign the request with the user credentials. The self.ping_url must be
223 defined if this method is being called.
224
225 """
226 logger.info('Pinging server for app_name %r, ping_url: %r, '
227 'email %r.', app_name, self.ping_url, email)
228 try:
229 url = self.ping_url.format(email=email)
230 except IndexError: # tuple index out of range
231 url = self.ping_url.format(email) # format the first substitution
232
233 if url == self.ping_url:
234 logger.debug('Original url (%r) could not be formatted, '
235 'appending email (%r).', self.ping_url, email)
236 url = self.ping_url + email
237
238 headers = utils.oauth_headers(url, credentials)
239 request = urllib2.Request(url, headers=headers)
240 logger.debug('Opening the url %r with urllib2.urlopen.',
241 request.get_full_url())
242 # This code is blocking, we should change this.
243 # I've tried with deferToThread an twisted.web.client.getPage
244 # but the returned deferred will never be fired (nataliabidart).
245 response = urllib2.urlopen(request)
246 logger.debug('Url opened. Response: %s.', response.code)
247 return defer.succeed(response)
248
249 @handle_exceptions(msg='Problem opening the Ubuntu SSO user interface')
250 def _show_ui(self, login_only):142 def _show_ui(self, login_only):
251 """Shows the UI, connect outcome signals."""143 """Shows the UI, connect outcome signals."""
252144 ui_exe_path = os.path.join(get_bin_dir(), self.ui_executable)
253 __import__(self.ui_module)145 args = [ui_exe_path]
254 gui = sys.modules[self.ui_module]146 for arg in ('app_name', 'help_text', 'ping_url', 'policy_url',
255147 'tc_url', 'window_id'):
256 self.inner = getattr(gui, self.ui_class)(app_name=self.app_name,148 value = getattr(self, arg)
257 tc_url=self.tc_url, help_text=self.help_text,149 if value:
258 window_id=self.window_id, login_only=login_only)150 args.append('--%s' % arg)
259151 args.append("%s" % str(value))
260 self.inner.login_success_callback = self._login_success_cb152
261 self.inner.registration_success_callback = self._login_success_cb153 if login_only:
262 self.inner.user_cancellation_callback = self._auth_denial_cb154 args.append('--login_only')
263155
264 @handle_exceptions(msg='Problem logging with email and password.')156 return_code = yield runner.spawn_program(args)
157 logger.info('_show_ui: received from the ui return code %r.',
158 return_code)
159
160 credentials = None
161 if return_code == USER_SUCCESS:
162 credentials = yield self.find_credentials()
163 elif return_code == USER_CANCELLATION:
164 raise UserCancellationError()
165 else:
166 raise CredentialsError(return_code)
167
168 defer.returnValue(credentials)
169
265 def _do_login(self, email, password):170 def _do_login(self, email, password):
266 """Login using email/password, connect outcome signals."""171 """Login using email/password, connect outcome signals."""
267 from ubuntu_sso.main import SSOLogin172 from ubuntu_sso.main import SSOLogin
@@ -279,62 +184,43 @@
279184
280 def LoginError(self, app_name, error):185 def LoginError(self, app_name, error):
281 """There was an error on login."""186 """There was an error on login."""
187 error = CredentialsError(error['errtype'])
282 d.errback(error)188 d.errback(error)
283189
284 def UserNotValidated(self, app_name, email):190 def UserNotValidated(self, app_name, email):
285 """User is not validated."""191 """User is not validated."""
286 d.callback(None)192 d.errback(UserNotValidatedError(email))
287193
288 # pylint: enable=C0103194 # pylint: enable=C0103
289195
290 self.inner = SSOLogin(proxy=DummyProxy())196 inner = SSOLogin(proxy=DummyProxy())
291 self.inner.login(app_name=self.app_name,197 inner.login(app_name=self.app_name,
292 email=email, password=password)198 email=email, password=password,
293199 ping_url=self.ping_url)
294 def _success(result):200
295 """Check if 'result' is a valid token, and callback properly."""201 d.addCallback(lambda _: self.find_credentials())
296 if result is not None:202 return d
297 return self._login_success_cb(self.app_name, email)203
298 else:
299 error_dict = {
300 'errtype': 'UserNotValidated',
301 'message': email,
302 }
303 self._error_cb(self.app_name, error_dict)
304
305 d.addCallback(_success)
306 d.addErrback(lambda f: self._error_cb(self.app_name, f.value))
307
308 @handle_failures(msg='Problem while retrieving credentials')
309 @defer.inlineCallbacks204 @defer.inlineCallbacks
310 def _login_or_register(self, login_only, email=None, password=None):205 def _login_or_register(self, login_only, email=None, password=None):
311 """Get credentials if found else prompt the GUI."""206 """Get credentials if found else prompt the GUI.
207
208 Will return either the credentials, or will raise UserCancellationError
209 if the user aborted the operation when the UI was opened.
210
211 """
312 logger.info("_login_or_register: login_only=%r email=%r.",212 logger.info("_login_or_register: login_only=%r email=%r.",
313 login_only, email)213 login_only, email)
314 token = yield self.find_credentials()214 token = yield self.find_credentials()
315 if token is not None and len(token) > 0:215 if not token:
316 self.success_cb(token)
317 elif token == {}:
318 if email and password:216 if email and password:
319 self._do_login(email, password)217 token = yield self._do_login(email, password)
320 else:218 else:
321 self._show_ui(login_only)219 token = yield self._show_ui(login_only)
322 else:220
323 # something went wrong with find_credentials, already handled.221 defer.returnValue(token)
324 logger.info('_login_or_register: call to "find_credentials" went '222
325 'wrong, and was already handled.')223 @handle_failures(msg='Problem while getting credentials from the keyring')
326
327 def error_cb(self, error_dict):
328 """Handle error and notify the caller."""
329 logger.error('Calling error callback at %r (error is %r).',
330 self._error_cb, error_dict)
331 self._error_cb(self.app_name, error_dict)
332
333 def success_cb(self, creds):
334 """Handle success and notify the caller."""
335 logger.debug('Calling success callback at %r.', self._success_cb)
336 self._success_cb(self.app_name, creds)
337
338 @defer.inlineCallbacks224 @defer.inlineCallbacks
339 def find_credentials(self):225 def find_credentials(self):
340 """Get the credentials for 'self.app_name'. Return {} if not there."""226 """Get the credentials for 'self.app_name'. Return {} if not there."""
@@ -343,20 +229,22 @@
343 'result is {}? %s', self.app_name, creds is None)229 'result is {}? %s', self.app_name, creds is None)
344 defer.returnValue(creds if creds is not None else {})230 defer.returnValue(creds if creds is not None else {})
345231
346 @defer.inlineCallbacks232 @handle_failures(msg='Problem while clearing credentials in the keyring')
347 def clear_credentials(self):233 def clear_credentials(self):
348 """Clear the credentials for 'self.app_name'."""234 """Clear the credentials for 'self.app_name'."""
349 yield Keyring().delete_credentials(self.app_name)235 return Keyring().delete_credentials(self.app_name)
350236
351 @defer.inlineCallbacks237 @handle_failures(msg='Problem while storing credentials in the keyring')
352 def store_credentials(self, token):238 def store_credentials(self, token):
353 """Store the credentials for 'self.app_name'."""239 """Store the credentials for 'self.app_name'."""
354 yield Keyring().set_credentials(self.app_name, token)240 return Keyring().set_credentials(self.app_name, token)
355241
242 @handle_failures(msg='Problem while performing register')
356 def register(self):243 def register(self):
357 """Get credentials if found else prompt the GUI to register."""244 """Get credentials if found else prompt the GUI to register."""
358 return self._login_or_register(login_only=False)245 return self._login_or_register(login_only=False)
359246
247 @handle_failures(msg='Problem while performing login')
360 def login(self, email=None, password=None):248 def login(self, email=None, password=None):
361 """Get credentials if found else prompt the GUI to login.249 """Get credentials if found else prompt the GUI to login.
362250
363251
=== modified file 'ubuntu_sso/gtk/__init__.py'
--- ubuntu_sso/gtk/__init__.py 2010-11-19 19:53:22 +0000
+++ ubuntu_sso/gtk/__init__.py 2012-02-14 22:04:20 +0000
@@ -1,8 +1,6 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2#2#
3# Author: Natalia Bidart <natalia.bidart@canonical.com>3# Copyright 2009-2012 Canonical Ltd.
4#
5# Copyright 2009-2010 Canonical Ltd.
6#4#
7# This program is free software: you can redistribute it and/or modify it5# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published6# under the terms of the GNU General Public License version 3, as published
97
=== modified file 'ubuntu_sso/gtk/gui.py'
--- ubuntu_sso/gtk/gui.py 2012-01-31 19:02:36 +0000
+++ ubuntu_sso/gtk/gui.py 2012-02-14 22:04:20 +0000
@@ -1,6 +1,6 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2#2#
3# Copyright 2010 Canonical Ltd.3# Copyright 2010-2012 Canonical Ltd.
4#4#
5# This program is free software: you can redistribute it and/or modify it5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published6# under the terms of the GNU General Public License version 3, as published
@@ -22,18 +22,23 @@
22import tempfile22import tempfile
23import webbrowser23import webbrowser
2424
25from functools import wraps25from functools import wraps, partial
2626
27import gtk27# pylint: disable=E0611,F0401
2828from gi.repository import Gdk, Gtk
29from gi.repository.GdkX11 import X11Window
30# pylint: enable=E0611,F0401
29from twisted.internet import defer31from twisted.internet import defer
3032
31from ubuntu_sso import (33from ubuntu_sso import (
32 main,34 main,
33 NO_OP,35 NO_OP,
36 USER_CANCELLATION,
37 USER_SUCCESS,
34 utils,38 utils,
35)39)
36from ubuntu_sso.logger import setup_logging40from ubuntu_sso.logger import setup_gui_logging
41from ubuntu_sso.utils import get_data_file
37from ubuntu_sso.utils.ui import (42from ubuntu_sso.utils.ui import (
38 CAPTCHA_LOAD_ERROR,43 CAPTCHA_LOAD_ERROR,
39 CAPTCHA_RELOAD_TOOLTIP,44 CAPTCHA_RELOAD_TOOLTIP,
@@ -43,7 +48,7 @@
43 ERROR,48 ERROR,
44 FIELD_REQUIRED,49 FIELD_REQUIRED,
45 FORGOTTEN_PASSWORD_BUTTON,50 FORGOTTEN_PASSWORD_BUTTON,
46 get_data_file,51 GENERIC_BACKEND_ERROR,
47 is_min_required_password,52 is_min_required_password,
48 is_correct_email,53 is_correct_email,
49 JOIN_HEADER_LABEL,54 JOIN_HEADER_LABEL,
@@ -72,7 +77,19 @@
72# pylint: disable=E110177# pylint: disable=E1101
7378
7479
75logger = setup_logging('ubuntu_sso.gui')80logger = setup_gui_logging('ubuntu_sso.gui.gtk')
81
82
83# pylint: disable=C0103
84def parse_color(color):
85 """Parse a string color into Gdk.Color."""
86 c = Gdk.RGBA()
87 result = c.parse(color)
88 if not result:
89 logger.warning('Could not parse color %r.', color)
90 return c
91# pylint: enable=C0103
92
7693
77# To be removed when Python bindings provide these constants94# To be removed when Python bindings provide these constants
78# as per http://code.google.com/p/pywebkitgtk/issues/detail?id=4495# as per http://code.google.com/p/pywebkitgtk/issues/detail?id=44
@@ -92,11 +109,8 @@
92109
93DEFAULT_WIDTH = 30110DEFAULT_WIDTH = 30
94# To be replaced by values from the theme (LP: #616526)111# To be replaced by values from the theme (LP: #616526)
95HELP_TEXT_COLOR = gtk.gdk.Color("#bfbfbf")112HELP_TEXT_COLOR = parse_color("#bfbfbf")
96WARNING_TEXT_COLOR = gtk.gdk.Color("red")113WARNING_TEXT_COLOR = parse_color("red")
97
98USER_CANCELLATION = 10
99LOGIN_SUCCESS = REGISTRATION_SUCCESS = 0
100114
101115
102def log_call(f):116def log_call(f):
@@ -111,9 +125,12 @@
111 return inner125 return inner
112126
113127
114class LabeledEntry(gtk.Entry):128class LabeledEntry(Gtk.Entry):
115 """An entry that displays the label within itself ina grey color."""129 """An entry that displays the label within itself ina grey color."""
116130
131 # Use of super on an old style class
132 # pylint: disable=E1002
133
117 def __init__(self, label, is_password=False, *args, **kwargs):134 def __init__(self, label, is_password=False, *args, **kwargs):
118 self.label = label135 self.label = label
119 self.is_password = is_password136 self.is_password = is_password
@@ -133,7 +150,8 @@
133 """Clear text and restore text color."""150 """Clear text and restore text color."""
134 self.set_text(self.get_text())151 self.set_text(self.get_text())
135152
136 self.modify_text(gtk.STATE_NORMAL, None) # restore to theme's default153 # restore to theme's default
154 self.override_color(Gtk.StateFlags.NORMAL, None)
137155
138 if self.is_password:156 if self.is_password:
139 self.set_visibility(False)157 self.set_visibility(False)
@@ -146,7 +164,7 @@
146 return164 return
147165
148 self.set_text(self.label)166 self.set_text(self.label)
149 self.modify_text(gtk.STATE_NORMAL, HELP_TEXT_COLOR)167 self.override_color(Gtk.StateFlags.NORMAL, HELP_TEXT_COLOR)
150168
151 if self.is_password:169 if self.is_password:
152 self.set_visibility(True)170 self.set_visibility(True)
@@ -163,7 +181,7 @@
163 def set_warning(self, warning_msg):181 def set_warning(self, warning_msg):
164 """Display warning as secondary icon, set 'warning_msg' as tooltip."""182 """Display warning as secondary icon, set 'warning_msg' as tooltip."""
165 self.warning = warning_msg183 self.warning = warning_msg
166 self.set_property('secondary-icon-stock', gtk.STOCK_DIALOG_WARNING)184 self.set_property('secondary-icon-stock', Gtk.STOCK_DIALOG_WARNING)
167 self.set_property('secondary-icon-sensitive', True)185 self.set_property('secondary-icon-sensitive', True)
168 self.set_property('secondary-icon-activatable', False)186 self.set_property('secondary-icon-activatable', False)
169 self.set_property('secondary-icon-tooltip-text', warning_msg)187 self.set_property('secondary-icon-tooltip-text', warning_msg)
@@ -185,8 +203,6 @@
185 logger.debug('UbuntuSSOClientGUI: app_name %r, kwargs %r.',203 logger.debug('UbuntuSSOClientGUI: app_name %r, kwargs %r.',
186 app_name, kwargs)204 app_name, kwargs)
187205
188 gtk.link_button_set_uri_hook(NO_OP)
189
190 self._captcha_filename = tempfile.mktemp()206 self._captcha_filename = tempfile.mktemp()
191 self._captcha_id = None207 self._captcha_id = None
192 self._signals_receivers = {}208 self._signals_receivers = {}
@@ -201,29 +217,22 @@
201 window_id = kwargs.get('window_id', 0)217 window_id = kwargs.get('window_id', 0)
202 self.close_callback = kwargs.get('close_callback', NO_OP)218 self.close_callback = kwargs.get('close_callback', NO_OP)
203 self.backend = None219 self.backend = None
204 # the following 3 callbacks will be removed as soon as
205 # the backend stop using them
206 self.login_success_callback = NO_OP
207 self.registration_success_callback = NO_OP
208 self.user_cancellation_callback = NO_OP
209
210 self.user_email = None220 self.user_email = None
211 self.user_password = None221 self.user_password = None
212222
213 ui_filename = get_data_file('gtk', 'ui.glade')223 ui_filename = get_data_file('gtk', 'ui.glade')
214 builder = gtk.Builder()224 builder = Gtk.Builder()
215 builder.add_from_file(ui_filename)225 builder.add_from_file(ui_filename)
216 builder.connect_signals(self)226 builder.connect_signals(self)
217227
218 self.widgets = []228 self.widgets = []
219 self.warnings = []229 self.warnings = []
220 self.cancels = []230 self.cancels = []
221 self.labels = []
222 for obj in builder.get_objects():231 for obj in builder.get_objects():
223 name = getattr(obj, 'name', None)232 name = getattr(obj, 'name', None)
224 if name is None and isinstance(obj, gtk.Buildable):233 if name is None and isinstance(obj, Gtk.Buildable):
225 # work around bug lp:507739234 # work around bug lp:507739
226 name = gtk.Buildable.get_name(obj)235 name = Gtk.Buildable.get_name(obj)
227 if name is None:236 if name is None:
228 logging.warn("%s has no name (??)", obj)237 logging.warn("%s has no name (??)", obj)
229 else:238 else:
@@ -235,9 +244,12 @@
235 if 'cancel_button' in name:244 if 'cancel_button' in name:
236 obj.connect('clicked', self.on_close_clicked)245 obj.connect('clicked', self.on_close_clicked)
237 self.cancels.append(obj)246 self.cancels.append(obj)
238 if 'label' in name:247
239 obj.connect('size-allocate', self.on_size_allocate)248 # Connect the activate-link signal here
240 self.labels.append(obj)249 # GtkBuilder in GTK 3 seems to not do this
250 self.login_button.connect('activate-link', self.on_activate_link)
251 self.forgotten_password_button.connect('activate-link',
252 self.on_activate_link)
241253
242 self.entries = (u'name_entry', u'email1_entry', u'email2_entry',254 self.entries = (u'name_entry', u'email1_entry', u'email2_entry',
243 u'password1_entry', u'password2_entry',255 u'password1_entry', u'password2_entry',
@@ -297,7 +309,10 @@
297 # still do everything as a standalone window. Also,309 # still do everything as a standalone window. Also,
298 # window_foreign_new may return None breaking set_transient_for.310 # window_foreign_new may return None breaking set_transient_for.
299 try:311 try:
300 win = gtk.gdk.window_foreign_new(window_id)312 display = Gdk.Display.get_default()
313 # this is not working, we need to create a XLib.window
314 # as a second parameter to foreign_new_for_display
315 win = X11Window.foreign_new_for_display(display, None)
301 self.window.realize()316 self.window.realize()
302 self.window.window.set_transient_for(win)317 self.window.window.set_transient_for(win)
303 except: # pylint: disable=W0702318 except: # pylint: disable=W0702
@@ -366,20 +381,21 @@
366381
367 def _add_spinner_to_container(self, container, legend=None):382 def _add_spinner_to_container(self, container, legend=None):
368 """Add a spinner to 'container'."""383 """Add a spinner to 'container'."""
369 spinner = gtk.Spinner()384 spinner = Gtk.Spinner()
370 spinner.start()385 spinner.start()
371386
372 label = gtk.Label()387 label = Gtk.Label()
373 if legend:388 if legend:
374 label.set_text(legend)389 label.set_text(legend)
375 else:390 else:
376 label.set_text(LOADING)391 label.set_text(LOADING)
377392
378 hbox = gtk.HBox(spacing=5)393 hbox = Gtk.HBox(spacing=5)
379 hbox.pack_start(spinner, expand=False)394 hbox.pack_start(spinner, expand=False, fill=True, padding=0)
380 hbox.pack_start(label, expand=False)395 hbox.pack_start(label, expand=False, fill=True, padding=0)
381396
382 alignment = gtk.Alignment(xalign=0.5, yalign=0.5)397 alignment = Gtk.Alignment(xalign=0.5, yalign=0.5,
398 xscale=0, yscale=0)
383 alignment.add(hbox)399 alignment.add(hbox)
384 alignment.show_all()400 alignment.show_all()
385401
@@ -394,7 +410,7 @@
394 def _set_warning_message(self, widget, message):410 def _set_warning_message(self, widget, message):
395 """Set 'message' as text for 'widget'."""411 """Set 'message' as text for 'widget'."""
396 widget.set_text(message)412 widget.set_text(message)
397 widget.modify_fg(gtk.STATE_NORMAL, WARNING_TEXT_COLOR)413 widget.override_color(Gtk.StateFlags.NORMAL, WARNING_TEXT_COLOR)
398 widget.show()414 widget.show()
399415
400 def _clear_warnings(self):416 def _clear_warnings(self):
@@ -409,6 +425,12 @@
409 text = widget.get_text()425 text = widget.get_text()
410 return bool(text and not text.isspace())426 return bool(text and not text.isspace())
411427
428 def _handle_error(self, remote_call, handler, error):
429 """Handle any error when calling the remote backend."""
430 logger.error('Remote call %r failed with: %r', remote_call, error)
431 errordict = {'message': GENERIC_BACKEND_ERROR}
432 handler(self.app_name, errordict)
433
412 # build pages434 # build pages
413435
414 def _append_pages(self):436 def _append_pages(self):
@@ -433,7 +455,7 @@
433455
434 def _append_page(self, page):456 def _append_page(self, page):
435 """Append 'page' to the 'window'."""457 """Append 'page' to the 'window'."""
436 self.content.append_page(page)458 self.content.append_page(page, None)
437459
438 def _set_header(self, header):460 def _set_header(self, header):
439 """Set 'header' as the window title and header."""461 """Set 'header' as the window title and header."""
@@ -464,16 +486,19 @@
464 logger.info('Calling generate_captcha with filename path at %r',486 logger.info('Calling generate_captcha with filename path at %r',
465 self._captcha_filename)487 self._captcha_filename)
466 self.warning_label.set_text('')488 self.warning_label.set_text('')
467 self.backend.generate_captcha(self.app_name, self._captcha_filename,489 f = self.backend.generate_captcha
468 reply_handler=NO_OP, error_handler=NO_OP)490 error_handler = partial(self._handle_error, f,
491 self.on_captcha_generation_error)
492 f(self.app_name, self._captcha_filename,
493 reply_handler=NO_OP, error_handler=error_handler)
469 self._set_captcha_loading()494 self._set_captcha_loading()
470495
471 def _set_captcha_loading(self):496 def _set_captcha_loading(self):
472 """Present a spinner to the user while the captcha is downloaded."""497 """Present a spinner to the user while the captcha is downloaded."""
473 self.captcha_image.hide()498 self.captcha_image.hide()
474 self._add_spinner_to_container(self.captcha_loading)499 self._add_spinner_to_container(self.captcha_loading)
475 white = gtk.gdk.Color('white')500 self.captcha_loading.override_background_color(Gtk.StateFlags.NORMAL,
476 self.captcha_loading.modify_bg(gtk.STATE_NORMAL, white)501 parse_color('white'))
477 self.captcha_loading.show_all()502 self.captcha_loading.show_all()
478 self.join_ok_button.set_sensitive(False)503 self.join_ok_button.set_sensitive(False)
479504
@@ -490,20 +515,26 @@
490 self.enter_details_vbox.header = JOIN_HEADER_LABEL % d515 self.enter_details_vbox.header = JOIN_HEADER_LABEL % d
491 self.enter_details_vbox.help_text = self.help_text516 self.enter_details_vbox.help_text = self.help_text
492 self.enter_details_vbox.default_widget = self.join_ok_button517 self.enter_details_vbox.default_widget = self.join_ok_button
493 self.join_ok_button.set_flags(gtk.CAN_DEFAULT)518 self.join_ok_button.set_can_default(True)
494519
495 self.enter_details_vbox.pack_start(self.name_entry, expand=False)520 self.enter_details_vbox.pack_start(self.name_entry,
521 expand=False, fill=True, padding=0)
496 self.enter_details_vbox.reorder_child(self.name_entry, 0)522 self.enter_details_vbox.reorder_child(self.name_entry, 0)
497 entry = self.captcha_solution_entry523 entry = self.captcha_solution_entry
498 self.captcha_solution_vbox.pack_start(entry, expand=False)524 self.captcha_solution_vbox.pack_start(entry,
525 expand=False, fill=True, padding=0)
499 msg = CAPTCHA_RELOAD_TOOLTIP526 msg = CAPTCHA_RELOAD_TOOLTIP
500 self.captcha_reload_button.set_tooltip_text(msg)527 self.captcha_reload_button.set_tooltip_text(msg)
501528
502 self.emails_hbox.pack_start(self.email1_entry, expand=False)529 self.emails_hbox.pack_start(self.email1_entry,
503 self.emails_hbox.pack_start(self.email2_entry, expand=False)530 expand=False, fill=True, padding=0)
531 self.emails_hbox.pack_start(self.email2_entry,
532 expand=False, fill=True, padding=0)
504533
505 self.passwords_hbox.pack_start(self.password1_entry, expand=False)534 self.passwords_hbox.pack_start(self.password1_entry,
506 self.passwords_hbox.pack_start(self.password2_entry, expand=False)535 expand=False, fill=True, padding=0)
536 self.passwords_hbox.pack_start(self.password2_entry,
537 expand=False, fill=True, padding=0)
507 help_msg = '<small>%s</small>' % PASSWORD_HELP538 help_msg = '<small>%s</small>' % PASSWORD_HELP
508 self.password_help_label.set_markup(help_msg)539 self.password_help_label.set_markup(help_msg)
509540
@@ -519,7 +550,7 @@
519 self.yes_to_tc_checkbutton.set_label(msg)550 self.yes_to_tc_checkbutton.set_label(msg)
520 self.tc_button.set_label(TC_BUTTON)551 self.tc_button.set_label(TC_BUTTON)
521 else:552 else:
522 self.tc_vbox.hide_all()553 self.tc_vbox.hide()
523 self.login_button.set_label(LOGIN_BUTTON_LABEL)554 self.login_button.set_label(LOGIN_BUTTON_LABEL)
524555
525 return self.enter_details_vbox556 return self.enter_details_vbox
@@ -528,7 +559,7 @@
528 """Build the Terms & Conditions page."""559 """Build the Terms & Conditions page."""
529 self.tc_browser_vbox.help_text = ''560 self.tc_browser_vbox.help_text = ''
530 self.tc_browser_vbox.default_widget = self.tc_back_button561 self.tc_browser_vbox.default_widget = self.tc_back_button
531 self.tc_browser_vbox.default_widget.set_flags(gtk.CAN_DEFAULT)562 self.tc_browser_vbox.default_widget.set_can_default(True)
532 return self.tc_browser_vbox563 return self.tc_browser_vbox
533564
534 def _build_processing_page(self):565 def _build_processing_page(self):
@@ -541,17 +572,16 @@
541 def _build_verify_email_page(self):572 def _build_verify_email_page(self):
542 """Build the verify email page."""573 """Build the verify email page."""
543 self.verify_email_vbox.default_widget = self.verify_token_button574 self.verify_email_vbox.default_widget = self.verify_token_button
544 self.verify_email_vbox.default_widget.set_flags(gtk.CAN_DEFAULT)575 self.verify_email_vbox.default_widget.set_can_default(True)
545576
546 self.verify_email_details_vbox.pack_start(self.email_token_entry,577 self.verify_email_details_vbox.pack_start(self.email_token_entry,
547 expand=False)578 expand=False, fill=True, padding=0)
548
549 return self.verify_email_vbox579 return self.verify_email_vbox
550580
551 def _build_finish_page(self):581 def _build_finish_page(self):
552 """Build the success page."""582 """Build the success page."""
553 self.finish_vbox.default_widget = self.finish_close_button583 self.finish_vbox.default_widget = self.finish_close_button
554 self.finish_vbox.default_widget.set_flags(gtk.CAN_DEFAULT)584 self.finish_vbox.default_widget.set_can_default(True)
555 self.finish_vbox.label = self.finish_label585 self.finish_vbox.label = self.finish_label
556 return self.finish_vbox586 return self.finish_vbox
557587
@@ -561,11 +591,13 @@
561 self.login_vbox.header = LOGIN_HEADER_LABEL % d591 self.login_vbox.header = LOGIN_HEADER_LABEL % d
562 self.login_vbox.help_text = CONNECT_HELP_LABEL % d592 self.login_vbox.help_text = CONNECT_HELP_LABEL % d
563 self.login_vbox.default_widget = self.login_ok_button593 self.login_vbox.default_widget = self.login_ok_button
564 self.login_vbox.default_widget.set_flags(gtk.CAN_DEFAULT)594 self.login_vbox.default_widget.set_can_default(True)
565595
566 self.login_details_vbox.pack_start(self.login_email_entry)596 self.login_details_vbox.pack_start(self.login_email_entry,
597 expand=True, fill=True, padding=0)
567 self.login_details_vbox.reorder_child(self.login_email_entry, 0)598 self.login_details_vbox.reorder_child(self.login_email_entry, 0)
568 self.login_details_vbox.pack_start(self.login_password_entry)599 self.login_details_vbox.pack_start(self.login_password_entry,
600 expand=True, fill=True, padding=0)
569 self.login_details_vbox.reorder_child(self.login_password_entry, 1)601 self.login_details_vbox.reorder_child(self.login_password_entry, 1)
570602
571 msg = FORGOTTEN_PASSWORD_BUTTON603 msg = FORGOTTEN_PASSWORD_BUTTON
@@ -580,12 +612,12 @@
580 text = REQUEST_PASSWORD_TOKEN_LABEL % {'app_name': self.app_label}612 text = REQUEST_PASSWORD_TOKEN_LABEL % {'app_name': self.app_label}
581 self.request_password_token_vbox.help_text = text613 self.request_password_token_vbox.help_text = text
582 btn = self.request_password_token_ok_button614 btn = self.request_password_token_ok_button
583 btn.set_flags(gtk.CAN_DEFAULT)615 btn.set_can_default(True)
584 self.request_password_token_vbox.default_widget = btn616 self.request_password_token_vbox.default_widget = btn
585617
586 entry = self.reset_email_entry618 entry = self.reset_email_entry
587 self.request_password_token_details_vbox.pack_start(entry,619 self.request_password_token_details_vbox.pack_start(entry,
588 expand=False)620 expand=False, fill=True, padding=0)
589 cb = self.on_reset_email_entry_changed621 cb = self.on_reset_email_entry_changed
590 self.reset_email_entry.connect('changed', cb)622 self.reset_email_entry.connect('changed', cb)
591 self.request_password_token_ok_button.set_label(NEXT)623 self.request_password_token_ok_button.set_label(NEXT)
@@ -598,13 +630,14 @@
598 self.set_new_password_vbox.header = RESET_PASSWORD630 self.set_new_password_vbox.header = RESET_PASSWORD
599 self.set_new_password_vbox.help_text = SET_NEW_PASSWORD_LABEL631 self.set_new_password_vbox.help_text = SET_NEW_PASSWORD_LABEL
600 btn = self.set_new_password_ok_button632 btn = self.set_new_password_ok_button
601 btn.set_flags(gtk.CAN_DEFAULT)633 btn.set_can_default(True)
602 self.set_new_password_vbox.default_widget = btn634 self.set_new_password_vbox.default_widget = btn
603635
604 for entry in (self.reset_code_entry,636 for entry in (self.reset_code_entry,
605 self.reset_password1_entry,637 self.reset_password1_entry,
606 self.reset_password2_entry):638 self.reset_password2_entry):
607 self.set_new_password_details_vbox.pack_start(entry, expand=False)639 self.set_new_password_details_vbox.pack_start(entry,
640 expand=False, fill=True, padding=0)
608641
609 cb = self.on_set_new_password_entries_changed642 cb = self.on_set_new_password_entries_changed
610 self.reset_code_entry.connect('changed', cb)643 self.reset_code_entry.connect('changed', cb)
@@ -645,6 +678,11 @@
645678
646 # GTK callbacks679 # GTK callbacks
647680
681 def destroy(self):
682 """Destroy this UI."""
683 self.window.hide()
684 self.window.destroy()
685
648 def connect(self, signal_name, handler, *args, **kwargs):686 def connect(self, signal_name, handler, *args, **kwargs):
649 """Connect 'signal_name' with 'handler'."""687 """Connect 'signal_name' with 'handler'."""
650 logger.debug('connect: signal %r, handler %r, args %r, kwargs, %r',688 logger.debug('connect: signal %r, handler %r, args %r, kwargs, %r',
@@ -661,9 +699,9 @@
661 self._done = True699 self._done = True
662 self._set_current_page(self.error_vbox)700 self._set_current_page(self.error_vbox)
663701
664 def on_size_allocate(self, widget, allocation):702 def on_activate_link(self, button):
665 """The widget can re rezised, embrase it!."""703 """Do nothing, used for LinkButtons that are used as regular ones."""
666 widget.set_size_request(allocation.width - 2, -1)704 return True
667705
668 def on_close_clicked(self, *args, **kwargs):706 def on_close_clicked(self, *args, **kwargs):
669 """Call self.close_callback if defined."""707 """Call self.close_callback if defined."""
@@ -678,16 +716,16 @@
678 self.window.hide()716 self.window.hide()
679717
680 # process any pending events before callbacking with result718 # process any pending events before callbacking with result
681 while gtk.events_pending():719 while Gtk.events_pending():
682 gtk.main_iteration()720 Gtk.main_iteration()
683721
684 return_code = LOGIN_SUCCESS722 return_code = USER_SUCCESS
685 if not self._done:723 if not self._done:
686 self.user_cancellation_callback(self.app_name)
687 return_code = USER_CANCELLATION724 return_code = USER_CANCELLATION
725 logger.info('Return code will be %r.', return_code)
688726
689 # call user defined callback727 # call user defined callback
690 logger.info('Calling custom close_callback %r with params %r, %r',728 logger.debug('Calling custom close_callback %r with params %r, %r',
691 self.close_callback, args, kwargs)729 self.close_callback, args, kwargs)
692 self.close_callback(*args, **kwargs)730 self.close_callback(*args, **kwargs)
693731
@@ -750,10 +788,14 @@
750 logger.info('Calling register_user with email %r, password <hidden>,' \788 logger.info('Calling register_user with email %r, password <hidden>,' \
751 ' name %r, captcha_id %r and captcha_solution %r.', email1,789 ' name %r, captcha_id %r and captcha_solution %r.', email1,
752 name, self._captcha_id, captcha_solution)790 name, self._captcha_id, captcha_solution)
791
753 f = self.backend.register_user792 f = self.backend.register_user
754 f(self.app_name, email1, password1, name,793 error_handler = partial(self._handle_error, f,
755 self._captcha_id, captcha_solution,794 self.on_user_registration_error)
756 reply_handler=NO_OP, error_handler=NO_OP)795 f(unicode(self.app_name), email1.decode('utf8'),
796 password1.decode('utf8'), name.decode('utf8'),
797 unicode(self._captcha_id), captcha_solution.decode('utf8'),
798 reply_handler=NO_OP, error_handler=error_handler)
757799
758 def on_verify_token_button_clicked(self, *args, **kwargs):800 def on_verify_token_button_clicked(self, *args, **kwargs):
759 """The user entered the email token, let's verify!"""801 """The user entered the email token, let's verify!"""
@@ -772,7 +814,7 @@
772814
773 args = (self.app_name, email, password, email_token)815 args = (self.app_name, email, password, email_token)
774 if self.ping_url:816 if self.ping_url:
775 f = self.backend.validate_email_with_ping817 f = self.backend.validate_email_and_ping
776 args = args + (self.ping_url,)818 args = args + (self.ping_url,)
777 else:819 else:
778 f = self.backend.validate_email820 f = self.backend.validate_email
@@ -780,7 +822,9 @@
780 logger.info('Calling validate_email with email %r, password <hidden>, '822 logger.info('Calling validate_email with email %r, password <hidden>, '
781 'app_name %r and email_token %r.', email, self.app_name,823 'app_name %r and email_token %r.', email, self.app_name,
782 email_token)824 email_token)
783 f(*args, reply_handler=NO_OP, error_handler=NO_OP)825 error_handler = partial(self._handle_error, f,
826 self.on_email_validation_error)
827 f(*args, reply_handler=NO_OP, error_handler=error_handler)
784828
785 self._set_current_page(self.processing_vbox)829 self._set_current_page(self.processing_vbox)
786830
@@ -809,12 +853,13 @@
809853
810 args = (self.app_name, email, password)854 args = (self.app_name, email, password)
811 if self.ping_url:855 if self.ping_url:
812 f = self.backend.login_with_ping856 f = self.backend.login_and_ping
813 args = args + (self.ping_url,)857 args = args + (self.ping_url,)
814 else:858 else:
815 f = self.backend.login859 f = self.backend.login
816860
817 f(*args, reply_handler=NO_OP, error_handler=NO_OP)861 error_handler = partial(self._handle_error, f, self.on_login_error)
862 f(*args, reply_handler=NO_OP, error_handler=error_handler)
818863
819 self._set_current_page(self.processing_vbox)864 self._set_current_page(self.processing_vbox)
820 self.user_email = email865 self.user_email = email
@@ -843,7 +888,10 @@
843888
844 logger.info('Calling request_password_reset_token with %r.', email)889 logger.info('Calling request_password_reset_token with %r.', email)
845 f = self.backend.request_password_reset_token890 f = self.backend.request_password_reset_token
846 f(self.app_name, email, reply_handler=NO_OP, error_handler=NO_OP)891 error_handler = partial(self._handle_error, f,
892 self.on_password_reset_error)
893 f(self.app_name, email,
894 reply_handler=NO_OP, error_handler=error_handler)
847895
848 self._set_current_page(self.processing_vbox)896 self._set_current_page(self.processing_vbox)
849897
@@ -894,16 +942,18 @@
894 logger.info('Calling set_new_password with email %r, token %r and ' \942 logger.info('Calling set_new_password with email %r, token %r and ' \
895 'new password: <hidden>.', email, token)943 'new password: <hidden>.', email, token)
896 f = self.backend.set_new_password944 f = self.backend.set_new_password
945 error_handler = partial(self._handle_error, f,
946 self.on_password_change_error)
897 f(self.app_name, email, token, password1,947 f(self.app_name, email, token, password1,
898 reply_handler=NO_OP, error_handler=NO_OP)948 reply_handler=NO_OP, error_handler=error_handler)
899949
900 self._set_current_page(self.processing_vbox)950 self._set_current_page(self.processing_vbox)
901951
902 def on_tc_button_clicked(self, *args, **kwargs):952 def on_tc_button_clicked(self, *args, **kwargs):
903 """The T&C button was clicked, create the browser and load terms."""953 """The T&C button was clicked, create the browser and load terms."""
904 # delay the import of webkit to be able to build without it954 # delay the import of webkit to be able to build without it
905 import webkit955 from gi.repository import WebKit # pylint: disable=E0611
906 browser = webkit.WebView()956 browser = WebKit.WebView()
907957
908 # The signal WebKitWebView::load-finished is deprecated and should not958 # The signal WebKitWebView::load-finished is deprecated and should not
909 # be used in newly-written code. Use the "load-status" property959 # be used in newly-written code. Use the "load-status" property
@@ -1023,7 +1073,6 @@
1023 @log_call1073 @log_call
1024 def on_email_validated(self, app_name, email, *args, **kwargs):1074 def on_email_validated(self, app_name, email, *args, **kwargs):
1025 """User email was successfully verified."""1075 """User email was successfully verified."""
1026 self.registration_success_callback(self.app_name, email)
1027 self.finish_success()1076 self.finish_success()
10281077
1029 @log_call1078 @log_call
@@ -1039,7 +1088,6 @@
1039 @log_call1088 @log_call
1040 def on_logged_in(self, app_name, email, *args, **kwargs):1089 def on_logged_in(self, app_name, email, *args, **kwargs):
1041 """User was successfully logged in."""1090 """User was successfully logged in."""
1042 self.login_success_callback(self.app_name, email)
1043 self.finish_success()1091 self.finish_success()
10441092
1045 @log_call1093 @log_call
10461094
=== modified file 'ubuntu_sso/gtk/main.py'
--- ubuntu_sso/gtk/main.py 2012-01-16 21:10:12 +0000
+++ ubuntu_sso/gtk/main.py 2012-02-14 22:04:20 +0000
@@ -16,34 +16,14 @@
1616
17"""Main module to open the GTK UI."""17"""Main module to open the GTK UI."""
1818
19import argparse19# pylint: disable=E0611
2020from gi.repository import Gtk
21import gtk21# pylint: enable=E0611
2222
23from ubuntu_sso.gtk.gui import UbuntuSSOClientGUI23from ubuntu_sso.gtk.gui import UbuntuSSOClientGUI
2424
2525
26def parse_args():
27 """Parse sys.argv options."""
28 parser = argparse.ArgumentParser(description='Open the GTK SSO UI.')
29 parser.add_argument('--app_name', required=True,
30 help='the name of the application to retrieve credentials for')
31 parser.add_argument('--ping_url', default='',
32 help='a link to be used as the ping url (to notify about new tokens)')
33 parser.add_argument('--tc_url', default='',
34 help='a link to be used as Terms & Conditions url')
35 parser.add_argument('--help_text', default='',
36 help='extra text that will be shown below the headers')
37 parser.add_argument('--window_id', type=int, default=0,
38 help='the window id to be set transient for the SSO GTK dialogs')
39 parser.add_argument('--login_only', action='store_true', default=False,
40 help='whether the SSO GTK UI should only offer login or not')
41
42 args = parser.parse_args()
43 return args
44
45
46def main(**kwargs):26def main(**kwargs):
47 """Start the GTK mainloop and open the main window."""27 """Start the GTK mainloop and open the main window."""
48 UbuntuSSOClientGUI(close_callback=gtk.main_quit, **kwargs)28 UbuntuSSOClientGUI(close_callback=Gtk.main_quit, **kwargs)
49 gtk.main()29 Gtk.main()
5030
=== modified file 'ubuntu_sso/gtk/tests/__init__.py'
--- ubuntu_sso/gtk/tests/__init__.py 2010-11-19 19:53:22 +0000
+++ ubuntu_sso/gtk/tests/__init__.py 2012-02-14 22:04:20 +0000
@@ -1,8 +1,6 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2#2#
3# Author: Natalia Bidart <natalia.bidart@canonical.com>3# Copyright 2009-2012 Canonical Ltd.
4#
5# Copyright 2009 Canonical Ltd.
6#4#
7# This program is free software: you can redistribute it and/or modify it5# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published6# under the terms of the GNU General Public License version 3, as published
97
=== modified file 'ubuntu_sso/gtk/tests/test_gui.py'
--- ubuntu_sso/gtk/tests/test_gui.py 2012-01-31 19:02:36 +0000
+++ ubuntu_sso/gtk/tests/test_gui.py 2012-02-14 22:04:20 +0000
@@ -21,8 +21,9 @@
2121
22from collections import defaultdict22from collections import defaultdict
2323
24import gtk24# pylint: disable=E0611
25import webkit25from gi.repository import Gdk, Gtk, WebKit
26# pylint: enable=E0611
2627
27from twisted.internet import defer28from twisted.internet import defer
28from twisted.trial.unittest import TestCase29from twisted.trial.unittest import TestCase
@@ -42,6 +43,9 @@
42# Instance of 'UbuntuSSOClientGUI' has no 'yyy' member43# Instance of 'UbuntuSSOClientGUI' has no 'yyy' member
43# pylint: disable=E1101,E110344# pylint: disable=E1101,E1103
4445
46# Use of super on an old style class
47# pylint: disable=E1002
48
4549
46class FakedSSOBackend(object):50class FakedSSOBackend(object):
47 """Fake a SSO Backend."""51 """Fake a SSO Backend."""
@@ -52,9 +56,9 @@
52 self._called = {}56 self._called = {}
53 self.callbacks = defaultdict(list)57 self.callbacks = defaultdict(list)
5458
55 for i in ('generate_captcha', 'login', 'login_with_ping',59 for i in ('generate_captcha', 'login', 'login_and_ping',
56 'register_user', 'validate_email',60 'register_user', 'validate_email',
57 'validate_email_with_ping',61 'validate_email_and_ping',
58 'request_password_reset_token',62 'request_password_reset_token',
59 'set_new_password'):63 'set_new_password'):
60 setattr(self, i, self._record_call(i))64 setattr(self, i, self._record_call(i))
@@ -99,7 +103,7 @@
99 self[prop_name] = newval103 self[prop_name] = newval
100104
101105
102class FakedEmbeddedBrowser(gtk.TextView):106class FakedEmbeddedBrowser(Gtk.TextView):
103 """Faked an embedded browser."""107 """Faked an embedded browser."""
104108
105 def __init__(self):109 def __init__(self):
@@ -156,6 +160,29 @@
156 """Set _called to True."""160 """Set _called to True."""
157 self._called = (args, kwargs)161 self._called = (args, kwargs)
158162
163 def assert_color_equal(self, rgba_color, gdk_color):
164 """Check that 'rgba_color' is the same as 'gdk_color'."""
165 tmp = Gdk.RGBA()
166 assert tmp.parse(gdk_color.to_string())
167
168 msg = 'Text color must be "%s" (got "%s" instead).'
169 self.assertEqual(rgba_color, tmp, msg % (rgba_color, tmp))
170
171 def assert_backend_called(self, method, *args, **kwargs):
172 """Check that 'method(*args, **kwargs)' was called in the backend."""
173 self.assertIn(method, self.ui.backend._called)
174
175 call = self.ui.backend._called[method]
176 self.assertEqual(call[0], args)
177
178 reply_handler = call[1].pop('reply_handler')
179 self.assertEqual(reply_handler, gui.NO_OP)
180
181 error_handler = call[1].pop('error_handler')
182 self.assertEqual(error_handler.func, self.ui._handle_error)
183
184 self.assertEqual(call[1], kwargs)
185
159186
160class LabeledEntryTestCase(BasicTestCase):187class LabeledEntryTestCase(BasicTestCase):
161 """Test suite for the labeled entry."""188 """Test suite for the labeled entry."""
@@ -168,9 +195,11 @@
168 self.entry = gui.LabeledEntry(label=self.label)195 self.entry = gui.LabeledEntry(label=self.label)
169196
170 # we need a window to be able to realize ourselves197 # we need a window to be able to realize ourselves
171 window = gtk.Window()198 window = Gtk.Window()
172 window.add(self.entry)199 window.add(self.entry)
173 window.show_all()200 window.show_all()
201 self.addCleanup(window.hide)
202 self.addCleanup(window.destroy)
174203
175 def grab_focus(self, focus_in=True):204 def grab_focus(self, focus_in=True):
176 """Grab focus on widget, if None use self.entry."""205 """Grab focus on widget, if None use self.entry."""
@@ -188,10 +217,9 @@
188 self.assertEqual(expected, actual, msg % (expected, actual))217 self.assertEqual(expected, actual, msg % (expected, actual))
189218
190 # text color is correct219 # text color is correct
191 msg = 'Text color must be "%s" (got "%s" instead).'
192 expected = gui.HELP_TEXT_COLOR220 expected = gui.HELP_TEXT_COLOR
193 actual = self.entry.style.text[gtk.STATE_NORMAL]221 actual = self.entry.get_style().text[Gtk.StateFlags.NORMAL]
194 self.assertEqual(expected, actual, msg % (expected, actual))222 self.assert_color_equal(expected, actual)
195223
196 def test_initial_text(self):224 def test_initial_text(self):
197 """Entry have the correct text at startup."""225 """Entry have the correct text at startup."""
@@ -218,11 +246,11 @@
218246
219 def test_text_defaults_to_theme_color_when_focus_in(self):247 def test_text_defaults_to_theme_color_when_focus_in(self):
220 """Entry restore its text color when focused in."""248 """Entry restore its text color when focused in."""
221 self.patch(self.entry, 'modify_text', self._set_called)249 self.patch(self.entry, 'override_color', self._set_called)
222250
223 self.grab_focus()251 self.grab_focus()
224252
225 self.assertEqual(((gtk.STATE_NORMAL, None), {}), self._called,253 self.assertEqual(((Gtk.StateFlags.NORMAL, None), {}), self._called,
226 'Entry text color must be restore on focus in.')254 'Entry text color must be restore on focus in.')
227255
228 def test_refill_entry_on_focus_out_if_no_input(self):256 def test_refill_entry_on_focus_out_if_no_input(self):
@@ -305,7 +333,7 @@
305 self.entry.set_warning(msg)333 self.entry.set_warning(msg)
306 self.assertEqual(self.entry.warning, msg)334 self.assertEqual(self.entry.warning, msg)
307 self.assertEqual(self.entry.get_property('secondary-icon-stock'),335 self.assertEqual(self.entry.get_property('secondary-icon-stock'),
308 gtk.STOCK_DIALOG_WARNING)336 Gtk.STOCK_DIALOG_WARNING)
309 self.assertEqual(self.entry.get_property('secondary-icon-sensitive'),337 self.assertEqual(self.entry.get_property('secondary-icon-sensitive'),
310 True)338 True)
311 self.assertEqual(self.entry.get_property('secondary-icon-activatable'),339 self.assertEqual(self.entry.get_property('secondary-icon-activatable'),
@@ -371,6 +399,7 @@
371 'tc_browser', 'login', 'request_password_token',399 'tc_browser', 'login', 'request_password_token',
372 'set_new_password')400 'set_new_password')
373 self.ui = self.gui_class(**self.kwargs)401 self.ui = self.gui_class(**self.kwargs)
402 self.addCleanup(self.ui.destroy)
374 self.error = {'message': UNKNOWN_ERROR}403 self.error = {'message': UNKNOWN_ERROR}
375404
376 def assert_entries_are_packed_to_ui(self, container_name, entries):405 def assert_entries_are_packed_to_ui(self, container_name, entries):
@@ -405,8 +434,8 @@
405434
406 # content color is correct435 # content color is correct
407 expected = gui.WARNING_TEXT_COLOR436 expected = gui.WARNING_TEXT_COLOR
408 actual = label.style.fg[gtk.STATE_NORMAL]437 actual = label.get_style().fg[Gtk.StateFlags.NORMAL]
409 self.assertEqual(expected, actual) # until realized this will fail438 self.assert_color_equal(expected, actual)
410439
411 def assert_correct_entry_warning(self, entry, message):440 def assert_correct_entry_warning(self, entry, message):
412 """Check that a warning is shown displaying 'message'."""441 """Check that a warning is shown displaying 'message'."""
@@ -533,16 +562,6 @@
533 entry = getattr(self.ui, name)562 entry = getattr(self.ui, name)
534 self.assertTrue(entry.get_activates_default(), msg % (name,))563 self.assertTrue(entry.get_activates_default(), msg % (name,))
535564
536 def test_label_size_allocated_is_connected(self):
537 """Labels have the size-allocate signal connected."""
538 msg = 'Label %r must have size-allocate connected.'
539 labels = [i for i in self.ui.widgets if 'label' in i]
540 for label in labels:
541 widget = getattr(self.ui, label)
542 widget.emit('size-allocate', gtk.gdk.Rectangle(1, 2, 3, 4))
543 self.assertEqual(widget.get_size_request(), (3 - 2, -1),
544 msg % (label,))
545
546 def test_password_fields_are_password(self):565 def test_password_fields_are_password(self):
547 """Password fields have the is_password flag set."""566 """Password fields have the is_password flag set."""
548 msg = '"%s" should be a password LabeledEntry instance.'567 msg = '"%s" should be a password LabeledEntry instance.'
@@ -573,28 +592,6 @@
573 """Main window has the proper icon."""592 """Main window has the proper icon."""
574 self.assertEqual('ubuntu-logo', self.ui.window.get_icon_name())593 self.assertEqual('ubuntu-logo', self.ui.window.get_icon_name())
575594
576 def test_transient_window_is_none_if_window_id_is_zero(self):
577 """The transient window is correct."""
578 self.patch(gtk.gdk, 'window_foreign_new', self._set_called)
579 self.gui_class(window_id=0, **self.kwargs)
580 self.assertFalse(self._called, 'set_transient_for must not be called.')
581
582 def test_transient_window_is_correct(self):
583 """The transient window is correct."""
584 xid = 5
585 self.patch(gtk.gdk, 'window_foreign_new', self._set_called)
586 self.gui_class(window_id=xid, **self.kwargs)
587 self.assertTrue(self.memento.check(logging.ERROR, 'set_transient_for'))
588 self.assertTrue(self.memento.check(logging.ERROR, str(xid)))
589 self.assertEqual(self._called, ((xid,), {}))
590
591 def test_transient_window_accepts_negative_id(self):
592 """The transient window accepts a negative window id."""
593 xid = -5
594 self.patch(gtk.gdk, 'window_foreign_new', self._set_called)
595 self.gui_class(window_id=xid, **self.kwargs)
596 self.assertEqual(self._called, ((xid,), {}))
597
598 def test_finish_success_shows_success_page(self):595 def test_finish_success_shows_success_page(self):
599 """When calling 'finish_success' the success page is shown."""596 """When calling 'finish_success' the success page is shown."""
600 self.ui.finish_success()597 self.ui.finish_success()
@@ -611,6 +608,42 @@
611 self.assertEqual(gui.ERROR, self.ui.finish_vbox.label.get_text())608 self.assertEqual(gui.ERROR, self.ui.finish_vbox.label.get_text())
612609
613610
611class SetTransientForTestCase(UbuntuSSOClientTestCase):
612 """Test suite for setting the window as transient for another one."""
613
614 def test_transient_window_is_none_if_window_id_is_zero(self):
615 """The transient window is correct."""
616 self.patch(gui.X11Window, 'foreign_new_for_display', self._set_called)
617 ui = self.gui_class(window_id=0, **self.kwargs)
618 self.addCleanup(ui.destroy)
619
620 self.assertFalse(self._called, 'set_transient_for must not be called.')
621
622 def test_transient_window_is_correct(self):
623 """The transient window is correct."""
624 xid = 5
625 self.patch(gui.X11Window, 'foreign_new_for_display', self._set_called)
626 ui = self.gui_class(window_id=xid, **self.kwargs)
627 self.addCleanup(ui.destroy)
628
629 self.assertTrue(self.memento.check(logging.ERROR, 'set_transient_for'))
630 self.assertTrue(self.memento.check(logging.ERROR, str(xid)))
631 self.assertEqual(self._called, ((xid,), {}))
632
633 def test_transient_window_accepts_negative_id(self):
634 """The transient window accepts a negative window id."""
635 xid = -5
636 self.patch(gui.X11Window, 'foreign_new_for_display', self._set_called)
637 ui = self.gui_class(window_id=xid, **self.kwargs)
638 self.addCleanup(ui.destroy)
639
640 self.assertEqual(self._called, ((xid,), {}))
641
642
643SetTransientForTestCase.skip = "Apparently, so far we can't use XLib " \
644"dynamic bindings to complete the call to X11Window.foreign_new_for_display."
645
646
614class EnterDetailsTestCase(UbuntuSSOClientTestCase):647class EnterDetailsTestCase(UbuntuSSOClientTestCase):
615 """Test suite for the user registration (enter details page)."""648 """Test suite for the user registration (enter details page)."""
616649
@@ -670,13 +703,8 @@
670 self.click_join_with_valid_data()703 self.click_join_with_valid_data()
671704
672 # assert register_user was called705 # assert register_user was called
673 expected = 'register_user'706 self.assert_backend_called('register_user',
674 self.assertIn(expected, self.ui.backend._called)707 APP_NAME, EMAIL, PASSWORD, NAME, CAPTCHA_ID, CAPTCHA_SOLUTION)
675 self.assertEqual(self.ui.backend._called[expected],
676 ((APP_NAME, EMAIL, PASSWORD, NAME, CAPTCHA_ID,
677 CAPTCHA_SOLUTION),
678 dict(reply_handler=gui.NO_OP,
679 error_handler=gui.NO_OP)))
680708
681 def test_join_ok_button_clicked_morphs_to_processing_page(self):709 def test_join_ok_button_clicked_morphs_to_processing_page(self):
682 """Clicking 'join_ok_button' presents the processing vbox."""710 """Clicking 'join_ok_button' presents the processing vbox."""
@@ -695,8 +723,8 @@
695 'processing_vbox must have two children.')723 'processing_vbox must have two children.')
696724
697 spinner, label = box.get_children()725 spinner, label = box.get_children()
698 self.assertIsInstance(spinner, gtk.Spinner)726 self.assertIsInstance(spinner, Gtk.Spinner)
699 self.assertIsInstance(label, gtk.Label)727 self.assertIsInstance(label, Gtk.Label)
700728
701 self.assertTrue(spinner.get_property('visible'),729 self.assertTrue(spinner.get_property('visible'),
702 'the processing spinner should be visible.')730 'the processing spinner should be visible.')
@@ -715,6 +743,8 @@
715 def test_captcha_filename_is_different_each_time(self):743 def test_captcha_filename_is_different_each_time(self):
716 """The captcha image is different each time."""744 """The captcha image is different each time."""
717 ui = self.gui_class(**self.kwargs)745 ui = self.gui_class(**self.kwargs)
746 self.addCleanup(ui.destroy)
747
718 self.assertNotEqual(self.ui._captcha_filename, ui._captcha_filename)748 self.assertNotEqual(self.ui._captcha_filename, ui._captcha_filename)
719749
720 def test_captcha_image_is_removed_when_exiting(self):750 def test_captcha_image_is_removed_when_exiting(self):
@@ -736,8 +766,8 @@
736 'captcha_loading must have two children.')766 'captcha_loading must have two children.')
737767
738 spinner, label = box.get_children()768 spinner, label = box.get_children()
739 self.assertIsInstance(spinner, gtk.Spinner)769 self.assertIsInstance(spinner, Gtk.Spinner)
740 self.assertIsInstance(label, gtk.Label)770 self.assertIsInstance(label, Gtk.Label)
741771
742 self.assertTrue(spinner.get_property('visible'),772 self.assertTrue(spinner.get_property('visible'),
743 'the captcha_loading spinner should be visible.')773 'the captcha_loading spinner should be visible.')
@@ -771,12 +801,8 @@
771 def test_captcha_image_is_requested_as_startup(self):801 def test_captcha_image_is_requested_as_startup(self):
772 """The captcha image is requested at startup."""802 """The captcha image is requested at startup."""
773 # assert generate_captcha was called803 # assert generate_captcha was called
774 expected = 'generate_captcha'804 self.assert_backend_called('generate_captcha',
775 self.assertIn(expected, self.ui.backend._called)805 APP_NAME, self.ui._captcha_filename)
776 self.assertEqual(self.ui.backend._called[expected],
777 ((APP_NAME, self.ui._captcha_filename),
778 dict(reply_handler=gui.NO_OP,
779 error_handler=gui.NO_OP)))
780806
781 def test_captcha_is_shown_when_available(self):807 def test_captcha_is_shown_when_available(self):
782 """The captcha image is shown when available."""808 """The captcha image is shown when available."""
@@ -872,7 +898,7 @@
872 @defer.inlineCallbacks898 @defer.inlineCallbacks
873 def setUp(self):899 def setUp(self):
874 yield super(TermsAndConditionsBrowserTestCase, self).setUp()900 yield super(TermsAndConditionsBrowserTestCase, self).setUp()
875 self.patch(webkit, 'WebView', FakedEmbeddedBrowser)901 self.patch(WebKit, 'WebView', FakedEmbeddedBrowser)
876902
877 self.ui.tc_button.clicked()903 self.ui.tc_button.clicked()
878 self.addCleanup(self.ui.tc_browser_vbox.hide)904 self.addCleanup(self.ui.tc_browser_vbox.hide)
@@ -968,10 +994,10 @@
968994
969 def test_navigation_requested_succeeds_for_no_clicking(self):995 def test_navigation_requested_succeeds_for_no_clicking(self):
970 """The navigation request succeeds when user hasn't clicked a link."""996 """The navigation request succeeds when user hasn't clicked a link."""
971 action = webkit.WebNavigationAction()997 action = WebKit.WebNavigationAction()
972 action.set_reason(gui.WEBKIT_WEB_NAVIGATION_REASON_OTHER)998 action.set_reason(gui.WEBKIT_WEB_NAVIGATION_REASON_OTHER)
973999
974 decision = webkit.WebPolicyDecision()1000 decision = WebKit.WebPolicyDecision()
975 decision.use = self._set_called1001 decision.use = self._set_called
9761002
977 kwargs = dict(browser=self.browser, frame=None, request=None,1003 kwargs = dict(browser=self.browser, frame=None, request=None,
@@ -981,10 +1007,10 @@
9811007
982 def test_navigation_requested_ignores_clicked_links(self):1008 def test_navigation_requested_ignores_clicked_links(self):
983 """The navigation request is ignored if a link was clicked."""1009 """The navigation request is ignored if a link was clicked."""
984 action = webkit.WebNavigationAction()1010 action = WebKit.WebNavigationAction()
985 action.set_reason(gui.WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED)1011 action.set_reason(gui.WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED)
9861012
987 decision = webkit.WebPolicyDecision()1013 decision = WebKit.WebPolicyDecision()
988 decision.ignore = self._set_called1014 decision.ignore = self._set_called
9891015
990 self.patch(gui.webbrowser, 'open', lambda *args, **kwargs: None)1016 self.patch(gui.webbrowser, 'open', lambda *args, **kwargs: None)
@@ -1007,11 +1033,11 @@
10071033
1008 """1034 """
1009 url = 'http://something.com/yadda'1035 url = 'http://something.com/yadda'
1010 action = webkit.WebNavigationAction()1036 action = WebKit.WebNavigationAction()
1011 action.set_reason(gui.WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED)1037 action.set_reason(gui.WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED)
1012 action.set_original_uri(url)1038 action.set_original_uri(url)
10131039
1014 decision = webkit.WebPolicyDecision()1040 decision = WebKit.WebPolicyDecision()
1015 decision.ignore = gui.NO_OP1041 decision.ignore = gui.NO_OP
10161042
1017 self.patch(gui.webbrowser, 'open', self._set_called)1043 self.patch(gui.webbrowser, 'open', self._set_called)
@@ -1098,12 +1124,7 @@
1098 def test_on_verify_token_button_clicked_calls_backend(self):1124 def test_on_verify_token_button_clicked_calls_backend(self):
1099 """Verify token button triggers call to backend."""1125 """Verify token button triggers call to backend."""
1100 self.click_verify_email_with_valid_data()1126 self.click_verify_email_with_valid_data()
1101 expected = self.method1127 self.assert_backend_called(self.method, *self.method_args)
1102 self.assertIn(expected, self.ui.backend._called)
1103 self.assertEqual(self.ui.backend._called[expected],
1104 (self.method_args,
1105 dict(reply_handler=gui.NO_OP,
1106 error_handler=gui.NO_OP)))
11071128
1108 def test_on_verify_token_button_clicked(self):1129 def test_on_verify_token_button_clicked(self):
1109 """Verify token uses cached user_email and user_password."""1130 """Verify token uses cached user_email and user_password."""
@@ -1117,10 +1138,7 @@
1117 self.ui.email_token_entry.set_text(EMAIL_TOKEN)1138 self.ui.email_token_entry.set_text(EMAIL_TOKEN)
11181139
1119 self.ui.on_verify_token_button_clicked()1140 self.ui.on_verify_token_button_clicked()
1120 self.assertEqual(self.ui.backend._called[self.method],1141 self.assert_backend_called(self.method, *tuple(method_args))
1121 (tuple(method_args),
1122 dict(reply_handler=gui.NO_OP,
1123 error_handler=gui.NO_OP)))
11241142
1125 def test_on_verify_token_button_shows_processing_page(self):1143 def test_on_verify_token_button_shows_processing_page(self):
1126 """Verify token button triggers call to backend."""1144 """Verify token button triggers call to backend."""
@@ -1211,7 +1229,7 @@
12111229
1212 kwargs = dict(app_name=APP_NAME, tc_url=TC_URL, help_text=HELP_TEXT,1230 kwargs = dict(app_name=APP_NAME, tc_url=TC_URL, help_text=HELP_TEXT,
1213 ping_url=PING_URL)1231 ping_url=PING_URL)
1214 method = 'validate_email_with_ping'1232 method = 'validate_email_and_ping'
1215 method_args = (APP_NAME, EMAIL, PASSWORD, EMAIL_TOKEN, PING_URL)1233 method_args = (APP_NAME, EMAIL, PASSWORD, EMAIL_TOKEN, PING_URL)
12161234
12171235
@@ -1455,13 +1473,7 @@
1455 def test_on_login_connect_button_clicked(self):1473 def test_on_login_connect_button_clicked(self):
1456 """Clicking login_ok_button calls backend.login."""1474 """Clicking login_ok_button calls backend.login."""
1457 self.click_connect_with_valid_data()1475 self.click_connect_with_valid_data()
14581476 self.assert_backend_called(self.method, *self.method_args)
1459 expected = self.method
1460 self.assertIn(expected, self.ui.backend._called)
1461 self.assertEqual(self.ui.backend._called[expected],
1462 (self.method_args,
1463 dict(reply_handler=gui.NO_OP,
1464 error_handler=gui.NO_OP)))
14651477
1466 def test_on_login_connect_button_clicked_morphs_to_processing_page(self):1478 def test_on_login_connect_button_clicked_morphs_to_processing_page(self):
1467 """Clicking login_ok_button morphs to the processing page."""1479 """Clicking login_ok_button morphs to the processing page."""
@@ -1543,7 +1555,7 @@
15431555
1544 kwargs = dict(app_name=APP_NAME, tc_url=TC_URL, help_text=HELP_TEXT,1556 kwargs = dict(app_name=APP_NAME, tc_url=TC_URL, help_text=HELP_TEXT,
1545 ping_url=PING_URL)1557 ping_url=PING_URL)
1546 method = 'login_with_ping'1558 method = 'login_and_ping'
1547 method_args = (APP_NAME, EMAIL, PASSWORD, PING_URL)1559 method_args = (APP_NAME, EMAIL, PASSWORD, PING_URL)
15481560
15491561
@@ -1665,12 +1677,8 @@
1665 def test_on_request_password_token_ok_button_clicked_calls_backend(self):1677 def test_on_request_password_token_ok_button_clicked_calls_backend(self):
1666 """Clicking request_password_token_ok_button the backend is called."""1678 """Clicking request_password_token_ok_button the backend is called."""
1667 self.click_request_password_token_with_valid_data()1679 self.click_request_password_token_with_valid_data()
1668 expected = 'request_password_reset_token'1680 self.assert_backend_called('request_password_reset_token',
1669 self.assertIn(expected, self.ui.backend._called)1681 APP_NAME, EMAIL)
1670 self.assertEqual(self.ui.backend._called[expected],
1671 ((APP_NAME, EMAIL),
1672 dict(reply_handler=gui.NO_OP,
1673 error_handler=gui.NO_OP)))
16741682
1675 def test_on_password_reset_token_sent_morphs_window(self):1683 def test_on_password_reset_token_sent_morphs_window(self):
1676 """When the reset token was sent, the reset password page is shown."""1684 """When the reset token was sent, the reset password page is shown."""
@@ -1805,12 +1813,8 @@
1805 def test_on_set_new_password_ok_button_clicked_calls_backend(self):1813 def test_on_set_new_password_ok_button_clicked_calls_backend(self):
1806 """Clicking set_new_password_ok_button the backend is called."""1814 """Clicking set_new_password_ok_button the backend is called."""
1807 self.click_set_new_password_with_valid_data()1815 self.click_set_new_password_with_valid_data()
1808 expected = 'set_new_password'1816 self.assert_backend_called('set_new_password',
1809 self.assertIn(expected, self.ui.backend._called)1817 APP_NAME, EMAIL, RESET_PASSWORD_TOKEN, PASSWORD)
1810 self.assertEqual(self.ui.backend._called[expected],
1811 ((APP_NAME, EMAIL, RESET_PASSWORD_TOKEN, PASSWORD),
1812 dict(reply_handler=gui.NO_OP,
1813 error_handler=gui.NO_OP)))
18141818
1815 def test_on_password_changed_shows_login_page(self):1819 def test_on_password_changed_shows_login_page(self):
1816 """When password was successfuly changed the login page is shown."""1820 """When password was successfuly changed the login page is shown."""
@@ -2070,10 +2074,6 @@
2070class ReturnCodeTestCase(UbuntuSSOClientTestCase):2074class ReturnCodeTestCase(UbuntuSSOClientTestCase):
2071 """Test the return codes."""2075 """Test the return codes."""
20722076
2073 LOGIN_SUCCESS = gui.LOGIN_SUCCESS
2074 REGISTRATION_SUCCESS = gui.REGISTRATION_SUCCESS
2075 USER_CANCELLATION = gui.USER_CANCELLATION
2076
2077 @defer.inlineCallbacks2077 @defer.inlineCallbacks
2078 def setUp(self):2078 def setUp(self):
2079 yield super(ReturnCodeTestCase, self).setUp()2079 yield super(ReturnCodeTestCase, self).setUp()
@@ -2081,7 +2081,7 @@
20812081
2082 def test_closing_main_window(self):2082 def test_closing_main_window(self):
2083 """When closing the main window, USER_CANCELLATION is called."""2083 """When closing the main window, USER_CANCELLATION is called."""
2084 self.ui.window.emit('delete-event', gtk.gdk.Event(gtk.gdk.DELETE))2084 self.ui.window.emit('delete-event', Gdk.Event())
2085 self.assertEqual(self._called, ((gui.USER_CANCELLATION,), {}))2085 self.assertEqual(self._called, ((gui.USER_CANCELLATION,), {}))
20862086
2087 def test_every_cancel_calls_proper_callback(self):2087 def test_every_cancel_calls_proper_callback(self):
@@ -2108,7 +2108,7 @@
2108 self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL)2108 self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL)
2109 self.ui.on_close_clicked()2109 self.ui.on_close_clicked()
21102110
2111 self.assertEqual(self._called, ((gui.REGISTRATION_SUCCESS,), {}))2111 self.assertEqual(self._called, ((gui.USER_SUCCESS,), {}))
21122112
2113 def test_on_email_validation_error_proper_callback_is_called(self):2113 def test_on_email_validation_error_proper_callback_is_called(self):
2114 """On EmailValidationError, USER_CANCELLATION is called."""2114 """On EmailValidationError, USER_CANCELLATION is called."""
@@ -2122,7 +2122,7 @@
2122 self.ui.on_logged_in(app_name=APP_NAME, email=EMAIL)2122 self.ui.on_logged_in(app_name=APP_NAME, email=EMAIL)
2123 self.ui.on_close_clicked()2123 self.ui.on_close_clicked()
21242124
2125 self.assertEqual(self._called, ((gui.LOGIN_SUCCESS,), {}))2125 self.assertEqual(self._called, ((gui.USER_SUCCESS,), {}))
21262126
2127 def test_on_login_error_proper_callback_is_called(self):2127 def test_on_login_error_proper_callback_is_called(self):
2128 """On LoginError, USER_CANCELLATION is called."""2128 """On LoginError, USER_CANCELLATION is called."""
@@ -2145,7 +2145,7 @@
2145 self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL)2145 self.ui.on_email_validated(app_name=APP_NAME, email=EMAIL)
2146 self.ui.on_close_clicked()2146 self.ui.on_close_clicked()
21472147
2148 self.assertEqual(self._called, ((gui.REGISTRATION_SUCCESS,), {}))2148 self.assertEqual(self._called, ((gui.USER_SUCCESS,), {}))
21492149
2150 def test_login_success_even_if_prior_login_error(self):2150 def test_login_success_even_if_prior_login_error(self):
2151 """Only one callback is called with the final outcome.2151 """Only one callback is called with the final outcome.
@@ -2160,7 +2160,7 @@
2160 self.ui.on_logged_in(app_name=APP_NAME, email=EMAIL)2160 self.ui.on_logged_in(app_name=APP_NAME, email=EMAIL)
2161 self.ui.on_close_clicked()2161 self.ui.on_close_clicked()
21622162
2163 self.assertEqual(self._called, ((gui.LOGIN_SUCCESS,), {}))2163 self.assertEqual(self._called, ((gui.USER_SUCCESS,), {}))
21642164
2165 def test_user_cancelation_even_if_prior_registration_error(self):2165 def test_user_cancelation_even_if_prior_registration_error(self):
2166 """Only one callback is called with the final outcome.2166 """Only one callback is called with the final outcome.
21672167
=== added file 'ubuntu_sso/gtk/tests/test_main.py'
--- ubuntu_sso/gtk/tests/test_main.py 1970-01-01 00:00:00 +0000
+++ ubuntu_sso/gtk/tests/test_main.py 2012-02-14 22:04:20 +0000
@@ -0,0 +1,39 @@
1# -*- coding: utf-8 -*-
2#
3# Copyright 2012 Canonical Ltd.
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program. If not, see <http://www.gnu.org/licenses/>.
16
17"""Tests for the main module."""
18
19from twisted.trial.unittest import TestCase
20
21from ubuntu_sso.gtk import main
22
23
24class BasicTestCase(TestCase):
25 """Test case with a helper tracker."""
26
27 def test_main(self):
28 """Calling main.main() a UI instance is created."""
29 called = []
30 self.patch(main, 'UbuntuSSOClientGUI',
31 lambda **kw: called.append(('GUI', kw)))
32 self.patch(main.Gtk, 'main',
33 lambda: called.append('main'))
34
35 kwargs = dict(foo='foo', bar='bar', baz='yadda', yadda=0)
36 main.main(**kwargs)
37
38 kwargs['close_callback'] = main.Gtk.main_quit
39 self.assertEqual(called, [('GUI', kwargs), 'main'])
040
=== modified file 'ubuntu_sso/keyring/__init__.py'
--- ubuntu_sso/keyring/__init__.py 2011-10-17 18:24:55 +0000
+++ ubuntu_sso/keyring/__init__.py 2012-02-14 22:04:20 +0000
@@ -29,8 +29,8 @@
2929
30logger = setup_logging("ubuntu_sso.keyring")30logger = setup_logging("ubuntu_sso.keyring")
3131
32TOKEN_SEPARATOR = ' @ '32TOKEN_SEPARATOR = u' @ '
33SEPARATOR_REPLACEMENT = ' AT '33SEPARATOR_REPLACEMENT = u' AT '
3434
35U1_APP_NAME = "Ubuntu One"35U1_APP_NAME = "Ubuntu One"
36U1_KEY_NAME = "UbuntuOne token for https://ubuntuone.com"36U1_KEY_NAME = "UbuntuOne token for https://ubuntuone.com"
@@ -41,26 +41,34 @@
4141
4242
43def gethostname():43def gethostname():
44 """Get the hostname, encoded in utf-8."""44 """Get the hostname, return the name as unicode."""
45 sys_encoding = sys.getfilesystemencoding()45 sys_encoding = sys.getfilesystemencoding()
46 hostname = socket.gethostname().decode(sys_encoding)46 hostname = socket.gethostname().decode(sys_encoding)
47 return hostname.encode("utf-8")47 return hostname
4848
4949
50def get_old_token_name(app_name):50def get_old_token_name(app_name):
51 """Build the token name (old style)."""51 """Build the token name (old style). Return an unicode."""
52 quoted_app_name = urllib.quote(app_name)52 quoted_app_name = urllib.quote(app_name)
53 computer_name = gethostname()53 computer_name = gethostname()
54 quoted_computer_name = urllib.quote(computer_name)54 quoted_computer_name = urllib.quote(computer_name)
55 return "%s - %s" % (quoted_app_name, quoted_computer_name)55
56 assert isinstance(computer_name, unicode)
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches