Merge lp:~mandel/ubuntu-sso-client/windows_ui_3 into lp:ubuntu-sso-client

Proposed by Manuel de la Peña
Status: Merged
Approved by: Manuel de la Peña
Approved revision: 746
Merged at revision: 695
Proposed branch: lp:~mandel/ubuntu-sso-client/windows_ui_3
Merge into: lp:ubuntu-sso-client
Prerequisite: lp:~mandel/ubuntu-sso-client/windows_ui_1
Diff against target: 2481 lines (+1634/-597)
11 files modified
data/qt/choose_sign_in.ui (+7/-7)
data/qt/current_user_sign_in.ui (+35/-82)
data/qt/email_verification.ui (+6/-31)
data/qt/setup_account.ui (+347/-442)
data/qt/terms_and_conditions.ui (+5/-35)
ubuntu_sso/qt/controllers.py (+260/-0)
ubuntu_sso/qt/gui.py (+438/-0)
ubuntu_sso/qt/tests/__init__.py (+1/-0)
ubuntu_sso/qt/tests/test_controllers.py (+318/-0)
ubuntu_sso/utils/tests/test_ui.py (+110/-0)
ubuntu_sso/utils/ui.py (+107/-0)
To merge this branch: bzr merge lp:~mandel/ubuntu-sso-client/windows_ui_3
Reviewer Review Type Date Requested Status
Alejandro J. Cura (community) fixes attached Approve
Roberto Alsina (community) Approve
Review via email: mp+55561@code.launchpad.net

This proposal supersedes a proposal from 2011-03-30.

Commit message

Provides the UI with the required controllers that will ensure that the navigation in the Wizard is the correct one. This branch does not yet provide the sso functionality.

Description of the change

Provides the UI with the required controllers that will ensure that the navigation in the Wizard is the correct one. This branch does not yet provide the sso functionality.

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

+1

review: Approve
Revision history for this message
Alejandro J. Cura (alecu) wrote :

Lovely branch!

A few fixes needed, but since they are not blocking, I'm approving anyway:

"Controlled to the ChooseSignIn view/widget." -> EPARSE
"Setting tranlated strings" -> +"s" times two
"Conroller for the setup account view" -> +"t"
"enxt" -> please unwrap
"strengh" -> +"t" times many
"Ui_ChooseSingInPage" -> "Sign"
"Represents and enhanced lineedit." -> "an"
"to the cation that will" -> "caption"?
"loginc" -> -"c"
"lwer" -> "lower"
"minimun" -> "minimum"

_strong, _medium, _weak_color -> move the QColors as constants
lines 1680, 1681 in the diff -> remove commented lines

review: Approve (fixes attached)
746. By Manuel de la Peña

Fixed mock test.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'data/qt/choose_sign_in.ui'
2--- data/qt/choose_sign_in.ui 2011-03-14 15:14:24 +0000
3+++ data/qt/choose_sign_in.ui 2011-04-05 13:47:53 +0000
4@@ -1,7 +1,7 @@
5 <?xml version="1.0" encoding="UTF-8"?>
6 <ui version="4.0">
7- <class>ChooseSingInWidget</class>
8- <widget class="QWidget" name="ChooseSingInWidget">
9+ <class>ChooseSignInPage</class>
10+ <widget class="QWizardPage" name="ChooseSingInPage">
11 <property name="geometry">
12 <rect>
13 <x>0</x>
14@@ -11,7 +11,7 @@
15 </rect>
16 </property>
17 <property name="windowTitle">
18- <string>Form</string>
19+ <string>WizardPage</string>
20 </property>
21 <layout class="QHBoxLayout" name="horizontalLayout">
22 <item>
23@@ -50,9 +50,9 @@
24 <item>
25 <layout class="QHBoxLayout" name="horizontalLayout_2">
26 <item>
27- <widget class="QPushButton" name="_existingAccountButton">
28+ <widget class="QPushButton" name="existing_account_button">
29 <property name="text">
30- <string>Sign me in with my existing account</string>
31+ <string/>
32 </property>
33 </widget>
34 </item>
35@@ -75,9 +75,9 @@
36 </spacer>
37 </item>
38 <item>
39- <widget class="QPushButton" name="_setUpAccountButton">
40+ <widget class="QPushButton" name="setup_account_button">
41 <property name="text">
42- <string>I don't have an account yet - sign me up</string>
43+ <string/>
44 </property>
45 </widget>
46 </item>
47
48=== modified file 'data/qt/current_user_sign_in.ui'
49--- data/qt/current_user_sign_in.ui 2011-03-14 12:18:54 +0000
50+++ data/qt/current_user_sign_in.ui 2011-04-05 13:47:53 +0000
51@@ -1,22 +1,19 @@
52 <?xml version="1.0" encoding="UTF-8"?>
53 <ui version="4.0">
54- <class>CurrentUserSignInWidget</class>
55- <widget class="QWidget" name="CurrentUserSignInWidget">
56+ <class>CurrentUserSignInPage</class>
57+ <widget class="QWizardPage" name="CurrentUserSignInPage">
58 <property name="geometry">
59 <rect>
60 <x>0</x>
61 <y>0</y>
62- <width>511</width>
63- <height>373</height>
64+ <width>400</width>
65+ <height>300</height>
66 </rect>
67 </property>
68 <property name="windowTitle">
69- <string>Form</string>
70- </property>
71- <property name="locale">
72- <locale language="English" country="UnitedStates"/>
73- </property>
74- <layout class="QHBoxLayout" name="horizontalLayout_2">
75+ <string>WizardPage</string>
76+ </property>
77+ <layout class="QHBoxLayout" name="horizontalLayout">
78 <item>
79 <layout class="QHBoxLayout" name="horizontalLayout_3">
80 <item>
81@@ -57,78 +54,34 @@
82 </property>
83 <layout class="QVBoxLayout" name="verticalLayout_3">
84 <item>
85- <widget class="QLabel" name="_titleLabel">
86- <property name="sizePolicy">
87- <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
88- <horstretch>0</horstretch>
89- <verstretch>0</verstretch>
90- </sizepolicy>
91- </property>
92- <property name="text">
93- <string>Sign in to Ubuntu One</string>
94- </property>
95- </widget>
96- </item>
97- <item>
98- <spacer name="verticalSpacer">
99- <property name="orientation">
100- <enum>Qt::Vertical</enum>
101- </property>
102- <property name="sizeType">
103- <enum>QSizePolicy::Fixed</enum>
104- </property>
105- <property name="sizeHint" stdset="0">
106- <size>
107- <width>20</width>
108- <height>10</height>
109- </size>
110- </property>
111- </spacer>
112- </item>
113- <item>
114 <layout class="QVBoxLayout" name="verticalLayout_2">
115 <item>
116- <widget class="QLabel" name="_emailLabel">
117- <property name="sizePolicy">
118- <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
119- <horstretch>0</horstretch>
120- <verstretch>0</verstretch>
121- </sizepolicy>
122- </property>
123- <property name="text">
124- <string>Email</string>
125- </property>
126- </widget>
127- </item>
128- <item>
129- <widget class="QLineEdit" name="_emailEdit"/>
130- </item>
131- <item>
132- <widget class="QLabel" name="_passwordLabel">
133- <property name="sizePolicy">
134- <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
135- <horstretch>0</horstretch>
136- <verstretch>0</verstretch>
137- </sizepolicy>
138- </property>
139- <property name="text">
140- <string>Password</string>
141- </property>
142- </widget>
143- </item>
144- <item>
145- <widget class="QLineEdit" name="_passwordEdit"/>
146- </item>
147- <item>
148- <widget class="QLabel" name="_forgotLabel">
149- <property name="sizePolicy">
150- <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
151- <horstretch>0</horstretch>
152- <verstretch>0</verstretch>
153- </sizepolicy>
154- </property>
155- <property name="text">
156- <string>Forgot password?</string>
157+ <widget class="QLineEdit" name="email_edit">
158+ <property name="placeholderText">
159+ <string/>
160+ </property>
161+ </widget>
162+ </item>
163+ <item>
164+ <widget class="QLineEdit" name="password_edit">
165+ <property name="echoMode">
166+ <enum>QLineEdit::Password</enum>
167+ </property>
168+ <property name="placeholderText">
169+ <string/>
170+ </property>
171+ </widget>
172+ </item>
173+ <item>
174+ <widget class="QLabel" name="forgot_label">
175+ <property name="sizePolicy">
176+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
177+ <horstretch>0</horstretch>
178+ <verstretch>0</verstretch>
179+ </sizepolicy>
180+ </property>
181+ <property name="text">
182+ <string/>
183 </property>
184 </widget>
185 </item>
186@@ -148,9 +101,9 @@
187 </spacer>
188 </item>
189 <item>
190- <widget class="QPushButton" name="_signInButton">
191+ <widget class="QPushButton" name="sign_in_button">
192 <property name="text">
193- <string>Sign in</string>
194+ <string/>
195 </property>
196 </widget>
197 </item>
198
199=== modified file 'data/qt/email_verification.ui'
200--- data/qt/email_verification.ui 2011-03-14 12:18:54 +0000
201+++ data/qt/email_verification.ui 2011-04-05 13:47:53 +0000
202@@ -1,7 +1,7 @@
203 <?xml version="1.0" encoding="UTF-8"?>
204 <ui version="4.0">
205- <class>EmailVerificationWidget</class>
206- <widget class="QWidget" name="EmailVerificationWidget">
207+ <class>EmailVerificationPage</class>
208+ <widget class="QWizardPage" name="EmailVerificationPage">
209 <property name="geometry">
210 <rect>
211 <x>0</x>
212@@ -11,7 +11,7 @@
213 </rect>
214 </property>
215 <property name="windowTitle">
216- <string>Form</string>
217+ <string>WizardPage</string>
218 </property>
219 <layout class="QHBoxLayout" name="horizontalLayout">
220 <item>
221@@ -35,34 +35,9 @@
222 <item>
223 <layout class="QVBoxLayout" name="verticalLayout">
224 <item>
225- <spacer name="verticalSpacer_3">
226- <property name="orientation">
227- <enum>Qt::Vertical</enum>
228- </property>
229- <property name="sizeHint" stdset="0">
230- <size>
231- <width>20</width>
232- <height>40</height>
233- </size>
234- </property>
235- </spacer>
236- </item>
237- <item>
238- <widget class="QLabel" name="_introLabel">
239- <property name="text">
240- <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;
241-&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;
242-p, li { white-space: pre-wrap; }
243-&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;
244-&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;We have sent you an email with a special code in it.&lt;/span&gt;&lt;/p&gt;
245-&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;Please check you email and enter the code here.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
246- </property>
247- </widget>
248- </item>
249- <item>
250- <widget class="QLineEdit" name="_verificationCodeEdit">
251+ <widget class="QLineEdit" name="verification_code_edit">
252 <property name="placeholderText">
253- <string>Enter email verification code</string>
254+ <string/>
255 </property>
256 </widget>
257 </item>
258@@ -82,7 +57,7 @@
259 </spacer>
260 </item>
261 <item>
262- <widget class="QPushButton" name="_nextButton">
263+ <widget class="QPushButton" name="next_button">
264 <property name="text">
265 <string>Next</string>
266 </property>
267
268=== modified file 'data/qt/setup_account.ui'
269--- data/qt/setup_account.ui 2011-03-14 12:18:54 +0000
270+++ data/qt/setup_account.ui 2011-04-05 13:47:53 +0000
271@@ -1,60 +1,259 @@
272 <?xml version="1.0" encoding="UTF-8"?>
273 <ui version="4.0">
274- <class>SetUpAccountWidget</class>
275- <widget class="QWidget" name="SetUpAccountWidget">
276+ <class>SetUpAccountPage</class>
277+ <widget class="QWizardPage" name="SetUpAccountPage">
278 <property name="geometry">
279 <rect>
280 <x>0</x>
281 <y>0</y>
282- <width>646</width>
283- <height>473</height>
284+ <width>415</width>
285+ <height>359</height>
286 </rect>
287 </property>
288 <property name="windowTitle">
289- <string>Form</string>
290+ <string>WizardPage</string>
291 </property>
292 <layout class="QHBoxLayout" name="horizontalLayout">
293 <item>
294- <layout class="QHBoxLayout" name="horizontalLayout_3">
295+ <layout class="QVBoxLayout" name="verticalLayout">
296 <item>
297- <spacer name="horizontalSpacer_2">
298+ <spacer name="verticalSpacer_3">
299 <property name="orientation">
300- <enum>Qt::Horizontal</enum>
301- </property>
302- <property name="sizeType">
303- <enum>QSizePolicy::Fixed</enum>
304+ <enum>Qt::Vertical</enum>
305 </property>
306 <property name="sizeHint" stdset="0">
307 <size>
308- <width>40</width>
309- <height>20</height>
310+ <width>20</width>
311+ <height>40</height>
312 </size>
313 </property>
314 </spacer>
315 </item>
316 <item>
317- <layout class="QVBoxLayout" name="verticalLayout">
318- <item>
319- <spacer name="verticalSpacer_3">
320- <property name="orientation">
321- <enum>Qt::Vertical</enum>
322- </property>
323- <property name="sizeHint" stdset="0">
324- <size>
325- <width>20</width>
326- <height>40</height>
327- </size>
328- </property>
329- </spacer>
330- </item>
331- <item>
332- <widget class="QFrame" name="_signInFrame">
333- <property name="frameShape">
334- <enum>QFrame::NoFrame</enum>
335- </property>
336- <layout class="QVBoxLayout" name="verticalLayout_3">
337- <item>
338- <widget class="QLabel" name="_titleLabel">
339+ <widget class="QFrame" name="_signInFrame">
340+ <property name="frameShape">
341+ <enum>QFrame::NoFrame</enum>
342+ </property>
343+ <layout class="QVBoxLayout" name="verticalLayout_3">
344+ <item>
345+ <layout class="QVBoxLayout" name="verticalLayout_2">
346+ <item>
347+ <layout class="QVBoxLayout" name="verticalLayout_7">
348+ <item>
349+ <layout class="QHBoxLayout" name="horizontalLayout_10">
350+ <item>
351+ <widget class="QLineEdit" name="first_name_edit">
352+ <property name="placeholderText">
353+ <string/>
354+ </property>
355+ </widget>
356+ </item>
357+ <item>
358+ <widget class="QLineEdit" name="last_name_edit">
359+ <property name="placeholderText">
360+ <string/>
361+ </property>
362+ </widget>
363+ </item>
364+ </layout>
365+ </item>
366+ <item>
367+ <layout class="QHBoxLayout" name="horizontalLayout_11">
368+ <item>
369+ <widget class="QLineEdit" name="email_edit">
370+ <property name="placeholderText">
371+ <string/>
372+ </property>
373+ </widget>
374+ </item>
375+ <item>
376+ <widget class="QLineEdit" name="confirm_email_edit">
377+ <property name="placeholderText">
378+ <string/>
379+ </property>
380+ </widget>
381+ </item>
382+ </layout>
383+ </item>
384+ <item>
385+ <layout class="QHBoxLayout" name="horizontalLayout_12">
386+ <item>
387+ <layout class="QVBoxLayout" name="verticalLayout_32">
388+ <item>
389+ <widget class="QLineEdit" name="password_edit">
390+ <property name="toolTip">
391+ <string>Your password must be at least 8 characters long and at least contain one number and one upper later.</string>
392+ </property>
393+ <property name="statusTip">
394+ <string/>
395+ </property>
396+ <property name="echoMode">
397+ <enum>QLineEdit::Password</enum>
398+ </property>
399+ <property name="placeholderText">
400+ <string/>
401+ </property>
402+ </widget>
403+ </item>
404+ <item>
405+ <widget class="QFrame" name="strenght_frame">
406+ <property name="sizePolicy">
407+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
408+ <horstretch>0</horstretch>
409+ <verstretch>0</verstretch>
410+ </sizepolicy>
411+ </property>
412+ <property name="minimumSize">
413+ <size>
414+ <width>0</width>
415+ <height>20</height>
416+ </size>
417+ </property>
418+ <property name="maximumSize">
419+ <size>
420+ <width>16777215</width>
421+ <height>30</height>
422+ </size>
423+ </property>
424+ <property name="locale">
425+ <locale language="English" country="UnitedStates"/>
426+ </property>
427+ <property name="frameShape">
428+ <enum>QFrame::StyledPanel</enum>
429+ </property>
430+ <property name="frameShadow">
431+ <enum>QFrame::Raised</enum>
432+ </property>
433+ <layout class="QHBoxLayout" name="horizontalLayout_15">
434+ <property name="spacing">
435+ <number>3</number>
436+ </property>
437+ <property name="leftMargin">
438+ <number>2</number>
439+ </property>
440+ <property name="topMargin">
441+ <number>0</number>
442+ </property>
443+ <property name="rightMargin">
444+ <number>2</number>
445+ </property>
446+ <property name="bottomMargin">
447+ <number>2</number>
448+ </property>
449+ <item>
450+ <widget class="QFrame" name="weak_frame">
451+ <property name="maximumSize">
452+ <size>
453+ <width>16777215</width>
454+ <height>10</height>
455+ </size>
456+ </property>
457+ <property name="frameShape">
458+ <enum>QFrame::StyledPanel</enum>
459+ </property>
460+ <property name="frameShadow">
461+ <enum>QFrame::Plain</enum>
462+ </property>
463+ <layout class="QVBoxLayout" name="verticalLayout_33">
464+ <property name="margin">
465+ <number>0</number>
466+ </property>
467+ </layout>
468+ </widget>
469+ </item>
470+ <item>
471+ <widget class="QFrame" name="medium_frame">
472+ <property name="maximumSize">
473+ <size>
474+ <width>16777215</width>
475+ <height>10</height>
476+ </size>
477+ </property>
478+ <property name="frameShape">
479+ <enum>QFrame::StyledPanel</enum>
480+ </property>
481+ <property name="frameShadow">
482+ <enum>QFrame::Plain</enum>
483+ </property>
484+ <layout class="QVBoxLayout" name="verticalLayout_34">
485+ <property name="margin">
486+ <number>0</number>
487+ </property>
488+ </layout>
489+ </widget>
490+ </item>
491+ <item>
492+ <widget class="QFrame" name="strong_frame">
493+ <property name="maximumSize">
494+ <size>
495+ <width>16777215</width>
496+ <height>10</height>
497+ </size>
498+ </property>
499+ <property name="frameShape">
500+ <enum>QFrame::StyledPanel</enum>
501+ </property>
502+ <property name="frameShadow">
503+ <enum>QFrame::Plain</enum>
504+ </property>
505+ <layout class="QVBoxLayout" name="verticalLayout_35">
506+ <property name="margin">
507+ <number>0</number>
508+ </property>
509+ </layout>
510+ </widget>
511+ </item>
512+ </layout>
513+ </widget>
514+ </item>
515+ <item>
516+ <spacer name="_strenghSpacer">
517+ <property name="orientation">
518+ <enum>Qt::Vertical</enum>
519+ </property>
520+ <property name="sizeHint" stdset="0">
521+ <size>
522+ <width>20</width>
523+ <height>5</height>
524+ </size>
525+ </property>
526+ </spacer>
527+ </item>
528+ </layout>
529+ </item>
530+ <item>
531+ <layout class="QVBoxLayout" name="verticalLayout_8">
532+ <item>
533+ <widget class="QLineEdit" name="confirm_password_edit">
534+ <property name="echoMode">
535+ <enum>QLineEdit::Password</enum>
536+ </property>
537+ <property name="placeholderText">
538+ <string/>
539+ </property>
540+ </widget>
541+ </item>
542+ <item>
543+ <spacer name="verticalSpacer_6">
544+ <property name="orientation">
545+ <enum>Qt::Vertical</enum>
546+ </property>
547+ <property name="sizeHint" stdset="0">
548+ <size>
549+ <width>20</width>
550+ <height>10</height>
551+ </size>
552+ </property>
553+ </spacer>
554+ </item>
555+ </layout>
556+ </item>
557+ </layout>
558+ </item>
559+ </layout>
560+ </item>
561+ <item>
562+ <widget class="QLabel" name="password_info_label">
563 <property name="sizePolicy">
564 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
565 <horstretch>0</horstretch>
566@@ -62,21 +261,7 @@
567 </sizepolicy>
568 </property>
569 <property name="text">
570- <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;
571-&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;
572-p, li { white-space: pre-wrap; }
573-&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;
574-&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:14pt;&quot;&gt;Create&lt;/span&gt;&lt;span style=&quot; font-size:14pt; font-weight:600;&quot;&gt; Ubuntu One&lt;/span&gt;&lt;span style=&quot; font-size:14pt;&quot;&gt; account&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
575- </property>
576- <property name="textFormat">
577- <enum>Qt::RichText</enum>
578- </property>
579- </widget>
580- </item>
581- <item>
582- <widget class="QLabel" name="_infoLabel">
583- <property name="text">
584- <string>Ubuntu One requires and Ubuntu Single Sign On (SSO) account. This process will allow you to create a new account, if you do not yet have one. </string>
585+ <string/>
586 </property>
587 <property name="wordWrap">
588 <bool>true</bool>
589@@ -84,417 +269,137 @@
590 </widget>
591 </item>
592 <item>
593- <spacer name="verticalSpacer">
594- <property name="orientation">
595- <enum>Qt::Vertical</enum>
596- </property>
597- <property name="sizeType">
598- <enum>QSizePolicy::Fixed</enum>
599- </property>
600- <property name="sizeHint" stdset="0">
601- <size>
602- <width>20</width>
603- <height>10</height>
604- </size>
605- </property>
606- </spacer>
607- </item>
608- <item>
609- <layout class="QVBoxLayout" name="verticalLayout_2">
610- <item>
611- <layout class="QVBoxLayout" name="verticalLayout_7">
612- <item>
613- <layout class="QHBoxLayout" name="horizontalLayout_10">
614- <item>
615- <widget class="QLineEdit" name="_firstNameEdit">
616- <property name="placeholderText">
617- <string>Name</string>
618- </property>
619- </widget>
620- </item>
621- <item>
622- <widget class="QLineEdit" name="_lastNameEdit">
623- <property name="placeholderText">
624- <string>Surname</string>
625- </property>
626- </widget>
627- </item>
628- </layout>
629- </item>
630- <item>
631- <layout class="QHBoxLayout" name="horizontalLayout_11">
632- <item>
633- <widget class="QLineEdit" name="_emailAddresslEdit">
634- <property name="placeholderText">
635- <string>Email address</string>
636- </property>
637- </widget>
638- </item>
639- <item>
640- <widget class="QLineEdit" name="_confirmEmailAddressEdit">
641- <property name="placeholderText">
642- <string>Re-type Email address</string>
643- </property>
644- </widget>
645- </item>
646- </layout>
647- </item>
648- <item>
649- <layout class="QHBoxLayout" name="horizontalLayout_12">
650- <item>
651- <layout class="QVBoxLayout" name="verticalLayout_32">
652- <item>
653- <widget class="QLineEdit" name="_passwordEdit">
654- <property name="toolTip">
655- <string>Your password must be at least 8 characters long and at least contain one number and one upper later.</string>
656- </property>
657- <property name="statusTip">
658- <string/>
659- </property>
660- <property name="echoMode">
661- <enum>QLineEdit::Password</enum>
662- </property>
663- <property name="placeholderText">
664- <string>Password</string>
665- </property>
666- </widget>
667- </item>
668- <item>
669- <widget class="QFrame" name="_strenghtFrame">
670- <property name="sizePolicy">
671- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
672- <horstretch>0</horstretch>
673- <verstretch>0</verstretch>
674- </sizepolicy>
675- </property>
676- <property name="minimumSize">
677- <size>
678- <width>0</width>
679- <height>20</height>
680- </size>
681- </property>
682- <property name="maximumSize">
683- <size>
684- <width>16777215</width>
685- <height>30</height>
686- </size>
687- </property>
688- <property name="locale">
689- <locale language="English" country="UnitedStates"/>
690- </property>
691- <property name="frameShape">
692- <enum>QFrame::StyledPanel</enum>
693- </property>
694- <property name="frameShadow">
695- <enum>QFrame::Raised</enum>
696- </property>
697- <layout class="QHBoxLayout" name="horizontalLayout_15">
698- <property name="spacing">
699- <number>3</number>
700- </property>
701- <property name="leftMargin">
702- <number>2</number>
703- </property>
704- <property name="topMargin">
705- <number>0</number>
706- </property>
707- <property name="rightMargin">
708- <number>2</number>
709- </property>
710- <property name="bottomMargin">
711- <number>2</number>
712- </property>
713- <item>
714- <widget class="QFrame" name="_weakFrame">
715- <property name="maximumSize">
716- <size>
717- <width>16777215</width>
718- <height>10</height>
719- </size>
720- </property>
721- <property name="frameShape">
722- <enum>QFrame::StyledPanel</enum>
723- </property>
724- <property name="frameShadow">
725- <enum>QFrame::Plain</enum>
726- </property>
727- <layout class="QVBoxLayout" name="verticalLayout_33">
728- <property name="margin">
729- <number>0</number>
730- </property>
731- </layout>
732- </widget>
733- </item>
734- <item>
735- <widget class="QFrame" name="_mediumFrame">
736- <property name="maximumSize">
737- <size>
738- <width>16777215</width>
739- <height>10</height>
740- </size>
741- </property>
742- <property name="frameShape">
743- <enum>QFrame::StyledPanel</enum>
744- </property>
745- <property name="frameShadow">
746- <enum>QFrame::Plain</enum>
747- </property>
748- <layout class="QVBoxLayout" name="verticalLayout_34">
749- <property name="margin">
750- <number>0</number>
751- </property>
752- </layout>
753- </widget>
754- </item>
755- <item>
756- <widget class="QFrame" name="_strongFrame">
757- <property name="maximumSize">
758- <size>
759- <width>16777215</width>
760- <height>10</height>
761- </size>
762- </property>
763- <property name="frameShape">
764- <enum>QFrame::StyledPanel</enum>
765- </property>
766- <property name="frameShadow">
767- <enum>QFrame::Plain</enum>
768- </property>
769- <layout class="QVBoxLayout" name="verticalLayout_35">
770- <property name="margin">
771- <number>0</number>
772- </property>
773- </layout>
774- </widget>
775- </item>
776- </layout>
777- </widget>
778- </item>
779- <item>
780- <spacer name="_strenghSpacer">
781- <property name="orientation">
782- <enum>Qt::Vertical</enum>
783- </property>
784- <property name="sizeHint" stdset="0">
785- <size>
786- <width>20</width>
787- <height>5</height>
788- </size>
789- </property>
790- </spacer>
791- </item>
792- </layout>
793- </item>
794- <item>
795- <layout class="QVBoxLayout" name="verticalLayout_8">
796- <item>
797- <widget class="QLineEdit" name="_confirmPasswordEdit">
798- <property name="echoMode">
799- <enum>QLineEdit::Password</enum>
800- </property>
801- <property name="placeholderText">
802- <string>Re-type password</string>
803- </property>
804- </widget>
805- </item>
806- <item>
807- <spacer name="verticalSpacer_6">
808- <property name="orientation">
809- <enum>Qt::Vertical</enum>
810- </property>
811- <property name="sizeHint" stdset="0">
812- <size>
813- <width>20</width>
814- <height>10</height>
815- </size>
816- </property>
817- </spacer>
818- </item>
819- </layout>
820- </item>
821- </layout>
822- </item>
823- </layout>
824- </item>
825- <item>
826- <widget class="QLabel" name="_passwordInfoLabel">
827+ <layout class="QVBoxLayout" name="verticalLayout_9">
828+ <item>
829+ <widget class="QFrame" name="frame_2">
830 <property name="sizePolicy">
831- <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
832+ <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
833 <horstretch>0</horstretch>
834 <verstretch>0</verstretch>
835 </sizepolicy>
836 </property>
837- <property name="text">
838- <string>The password must have a minimum of 8 characters and include one uppercase character and one number.</string>
839- </property>
840- <property name="wordWrap">
841- <bool>true</bool>
842- </property>
843- </widget>
844- </item>
845- <item>
846- <layout class="QVBoxLayout" name="verticalLayout_9">
847- <item>
848- <widget class="QFrame" name="frame_2">
849- <property name="sizePolicy">
850- <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
851- <horstretch>0</horstretch>
852- <verstretch>0</verstretch>
853- </sizepolicy>
854- </property>
855- <property name="frameShape">
856- <enum>QFrame::StyledPanel</enum>
857- </property>
858- <property name="frameShadow">
859- <enum>QFrame::Raised</enum>
860- </property>
861- <layout class="QHBoxLayout" name="horizontalLayout_16">
862- <property name="leftMargin">
863- <number>0</number>
864- </property>
865- <item>
866- <widget class="QGraphicsView" name="graphicsView">
867- <property name="sizePolicy">
868- <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
869- <horstretch>0</horstretch>
870- <verstretch>0</verstretch>
871- </sizepolicy>
872- </property>
873- <property name="maximumSize">
874- <size>
875- <width>16777215</width>
876- <height>70</height>
877- </size>
878- </property>
879- <property name="verticalScrollBarPolicy">
880- <enum>Qt::ScrollBarAlwaysOff</enum>
881- </property>
882- <property name="horizontalScrollBarPolicy">
883- <enum>Qt::ScrollBarAlwaysOff</enum>
884- </property>
885- <property name="interactive">
886- <bool>false</bool>
887- </property>
888- <property name="sceneRect">
889- <rectf>
890- <x>0.000000000000000</x>
891- <y>0.000000000000000</y>
892- <width>0.000000000000000</width>
893- <height>0.000000000000000</height>
894- </rectf>
895- </property>
896- </widget>
897- </item>
898- <item>
899- <widget class="QLabel" name="_refreshLabel">
900- <property name="sizePolicy">
901- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
902- <horstretch>0</horstretch>
903- <verstretch>0</verstretch>
904- </sizepolicy>
905- </property>
906- <property name="locale">
907- <locale language="English" country="UnitedStates"/>
908- </property>
909- <property name="text">
910- <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;
911+ <property name="frameShape">
912+ <enum>QFrame::StyledPanel</enum>
913+ </property>
914+ <property name="frameShadow">
915+ <enum>QFrame::Raised</enum>
916+ </property>
917+ <layout class="QHBoxLayout" name="horizontalLayout_16">
918+ <property name="leftMargin">
919+ <number>0</number>
920+ </property>
921+ <item>
922+ <widget class="QLabel" name="captcha_view">
923+ <property name="frameShape">
924+ <enum>QFrame::Box</enum>
925+ </property>
926+ <property name="text">
927+ <string/>
928+ </property>
929+ </widget>
930+ </item>
931+ <item>
932+ <widget class="QLabel" name="refresh_label">
933+ <property name="sizePolicy">
934+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
935+ <horstretch>0</horstretch>
936+ <verstretch>0</verstretch>
937+ </sizepolicy>
938+ </property>
939+ <property name="locale">
940+ <locale language="English" country="UnitedStates"/>
941+ </property>
942+ <property name="text">
943+ <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;
944 &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;
945 p, li { white-space: pre-wrap; }
946 &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;
947 &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>
948- </property>
949- <property name="wordWrap">
950- <bool>true</bool>
951- </property>
952- </widget>
953- </item>
954- </layout>
955- </widget>
956- </item>
957- <item>
958- <widget class="QLineEdit" name="lineEdit">
959- <property name="locale">
960- <locale language="English" country="UnitedStates"/>
961- </property>
962- <property name="inputMask">
963- <string/>
964- </property>
965- <property name="text">
966- <string/>
967- </property>
968- <property name="placeholderText">
969- <string>Type the characters above</string>
970- </property>
971- </widget>
972- </item>
973- </layout>
974- </item>
975- <item>
976- <widget class="QCheckBox" name="_termsCheckbox">
977- <property name="text">
978- <string>I agree with the Ubuntu One terms and conditions</string>
979- </property>
980- </widget>
981- </item>
982- <item>
983- <layout class="QHBoxLayout" name="horizontalLayout_4">
984- <property name="spacing">
985- <number>0</number>
986- </property>
987- <item>
988- <widget class="QPushButton" name="_termsButton">
989- <property name="text">
990- <string>Show Terms and Conditions</string>
991- </property>
992- </widget>
993- </item>
994- <item>
995- <spacer name="horizontalSpacer_3">
996- <property name="orientation">
997- <enum>Qt::Horizontal</enum>
998- </property>
999- <property name="sizeHint" stdset="0">
1000- <size>
1001- <width>40</width>
1002- <height>20</height>
1003- </size>
1004- </property>
1005- </spacer>
1006- </item>
1007- </layout>
1008+ </property>
1009+ <property name="wordWrap">
1010+ <bool>true</bool>
1011+ </property>
1012+ </widget>
1013+ </item>
1014+ </layout>
1015+ </widget>
1016+ </item>
1017+ <item>
1018+ <widget class="QLineEdit" name="captcha_solution_edit">
1019+ <property name="locale">
1020+ <locale language="English" country="UnitedStates"/>
1021+ </property>
1022+ <property name="inputMask">
1023+ <string/>
1024+ </property>
1025+ <property name="text">
1026+ <string/>
1027+ </property>
1028+ <property name="placeholderText">
1029+ <string/>
1030+ </property>
1031+ </widget>
1032+ </item>
1033+ </layout>
1034+ </item>
1035+ <item>
1036+ <widget class="QCheckBox" name="terms_checkbox">
1037+ <property name="text">
1038+ <string/>
1039+ </property>
1040+ </widget>
1041+ </item>
1042+ <item>
1043+ <layout class="QHBoxLayout" name="horizontalLayout_4">
1044+ <property name="spacing">
1045+ <number>0</number>
1046+ </property>
1047+ <item>
1048+ <widget class="QPushButton" name="terms_button">
1049+ <property name="text">
1050+ <string/>
1051+ </property>
1052+ </widget>
1053+ </item>
1054+ <item>
1055+ <spacer name="horizontalSpacer_3">
1056+ <property name="orientation">
1057+ <enum>Qt::Horizontal</enum>
1058+ </property>
1059+ <property name="sizeHint" stdset="0">
1060+ <size>
1061+ <width>40</width>
1062+ <height>20</height>
1063+ </size>
1064+ </property>
1065+ </spacer>
1066+ </item>
1067+ <item>
1068+ <widget class="QPushButton" name="set_up_button">
1069+ <property name="enabled">
1070+ <bool>false</bool>
1071+ </property>
1072+ <property name="text">
1073+ <string/>
1074+ </property>
1075+ </widget>
1076 </item>
1077 </layout>
1078 </item>
1079 </layout>
1080- </widget>
1081- </item>
1082- <item>
1083- <spacer name="verticalSpacer_2">
1084- <property name="orientation">
1085- <enum>Qt::Vertical</enum>
1086- </property>
1087- <property name="sizeHint" stdset="0">
1088- <size>
1089- <width>20</width>
1090- <height>40</height>
1091- </size>
1092- </property>
1093- </spacer>
1094- </item>
1095- </layout>
1096+ </item>
1097+ </layout>
1098+ </widget>
1099 </item>
1100 <item>
1101- <spacer name="horizontalSpacer">
1102+ <spacer name="verticalSpacer_2">
1103 <property name="orientation">
1104- <enum>Qt::Horizontal</enum>
1105- </property>
1106- <property name="sizeType">
1107- <enum>QSizePolicy::Fixed</enum>
1108+ <enum>Qt::Vertical</enum>
1109 </property>
1110 <property name="sizeHint" stdset="0">
1111 <size>
1112- <width>40</width>
1113- <height>20</height>
1114+ <width>20</width>
1115+ <height>40</height>
1116 </size>
1117 </property>
1118 </spacer>
1119
1120=== modified file 'data/qt/terms_and_conditions.ui'
1121--- data/qt/terms_and_conditions.ui 2011-03-14 12:22:58 +0000
1122+++ data/qt/terms_and_conditions.ui 2011-04-05 13:47:53 +0000
1123@@ -1,7 +1,7 @@
1124 <?xml version="1.0" encoding="UTF-8"?>
1125 <ui version="4.0">
1126- <class>TermsAndConditionsWidget</class>
1127- <widget class="QWidget" name="TermsAndConditionsWidget">
1128+ <class>TosPage</class>
1129+ <widget class="QWizardPage" name="TosPage">
1130 <property name="geometry">
1131 <rect>
1132 <x>0</x>
1133@@ -11,7 +11,7 @@
1134 </rect>
1135 </property>
1136 <property name="windowTitle">
1137- <string>Form</string>
1138+ <string>WizardPage</string>
1139 </property>
1140 <layout class="QHBoxLayout" name="horizontalLayout">
1141 <item>
1142@@ -51,36 +51,6 @@
1143 </spacer>
1144 </item>
1145 <item>
1146- <widget class="QLabel" name="_titleLabel">
1147- <property name="text">
1148- <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;
1149-&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;
1150-p, li { white-space: pre-wrap; }
1151-&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;
1152-&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:14pt;&quot;&gt;Term and Conditions&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
1153- </property>
1154- <property name="textFormat">
1155- <enum>Qt::RichText</enum>
1156- </property>
1157- </widget>
1158- </item>
1159- <item>
1160- <spacer name="verticalSpacer">
1161- <property name="orientation">
1162- <enum>Qt::Vertical</enum>
1163- </property>
1164- <property name="sizeType">
1165- <enum>QSizePolicy::Fixed</enum>
1166- </property>
1167- <property name="sizeHint" stdset="0">
1168- <size>
1169- <width>20</width>
1170- <height>10</height>
1171- </size>
1172- </property>
1173- </spacer>
1174- </item>
1175- <item>
1176 <widget class="QScrollArea" name="scrollArea">
1177 <property name="widgetResizable">
1178 <bool>true</bool>
1179@@ -91,12 +61,12 @@
1180 <x>0</x>
1181 <y>0</y>
1182 <width>284</width>
1183- <height>139</height>
1184+ <height>184</height>
1185 </rect>
1186 </property>
1187 <layout class="QHBoxLayout" name="horizontalLayout_2">
1188 <item>
1189- <widget class="QWebView" name="_termsWebkit">
1190+ <widget class="QWebView" name="terms_webkit">
1191 <property name="url">
1192 <url>
1193 <string>about:blank</string>
1194
1195=== added file 'ubuntu_sso/qt/controllers.py'
1196--- ubuntu_sso/qt/controllers.py 1970-01-01 00:00:00 +0000
1197+++ ubuntu_sso/qt/controllers.py 2011-04-05 13:47:53 +0000
1198@@ -0,0 +1,260 @@
1199+# -*- coding: utf-8 -*-
1200+# Author: Manuel de la Pena <manuel@canonical.com>
1201+#
1202+# Copyright 2011 Canonical Ltd.
1203+#
1204+# This program is free software: you can redistribute it and/or modify it
1205+# under the terms of the GNU General Public License version 3, as published
1206+# by the Free Software Foundation.
1207+#
1208+# This program is distributed in the hope that it will be useful, but
1209+# WITHOUT ANY WARRANTY; without even the implied warranties of
1210+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1211+# PURPOSE. See the GNU General Public License for more details.
1212+#
1213+# You should have received a copy of the GNU General Public License along
1214+# with this program. If not, see <http://www.gnu.org/licenses/>.
1215+"""Controllers with the logic of the UI."""
1216+
1217+from PyQt4.QtCore import QUrl
1218+
1219+from ubuntu_sso.logger import setup_logging
1220+from ubuntu_sso.utils.ui import (
1221+ CAPTCHA_SOLUTION_ENTRY,
1222+ EMAIL1_ENTRY,
1223+ EMAIL2_ENTRY,
1224+ EXISTING_ACCOUNT_CHOICE_BUTTON,
1225+ FORGOTTEN_PASSWORD_BUTTON,
1226+ JOIN_HEADER_LABEL,
1227+ NAME_ENTRY,
1228+ PASSWORD1_ENTRY,
1229+ PASSWORD2_ENTRY,
1230+ PASSWORD_HELP,
1231+ SET_UP_ACCOUNT_CHOICE_BUTTON,
1232+ SET_UP_ACCOUNT_BUTTON,
1233+ SIGN_IN_BUTTON,
1234+ SURNAME_ENTRY,
1235+ TC_BUTTON,
1236+ VERIFY_EMAIL_TITLE,
1237+ VERIFY_EMAIL_CONTENT,
1238+ YES_TO_TC,
1239+ get_password_strength,
1240+ is_min_required_password)
1241+
1242+
1243+logger = setup_logging('ubuntu_sso.controllers')
1244+
1245+
1246+class ChooseSignInController(object):
1247+ """Controlled to the ChooseSignIn view/widget."""
1248+
1249+ def __init__(self, title='', existing_account_id=1,
1250+ new_account_id=2):
1251+ """Create a new instance to manage the view."""
1252+ self._title = title
1253+ self._existing_account_id = existing_account_id
1254+ self._new_account_id = new_account_id
1255+
1256+ # use an ugly name just so have a simlar api as found in PyQt
1257+ #pylint: disable=C0103
1258+ def setupUi(self, view):
1259+ """Perform the required actions to set up the ui."""
1260+ view.setTitle(self._title)
1261+ self._set_up_translated_strings(view)
1262+ self._connect_buttons(view)
1263+ #pylint: enable=C0103
1264+
1265+ def _set_up_translated_strings(self, view):
1266+ """Set the correct strings for the UI."""
1267+ view.existing_account_button.setText(EXISTING_ACCOUNT_CHOICE_BUTTON)
1268+ view.new_account_button.setText(SET_UP_ACCOUNT_CHOICE_BUTTON)
1269+
1270+ def _connect_buttons(self, view):
1271+ """Connect the buttons to the actions to perform."""
1272+ view.existing_account_button.clicked.connect(
1273+ lambda: self._set_next_existing(view))
1274+ view.new_account_button.clicked.connect(
1275+ lambda: self._set_next_new(view))
1276+
1277+ def _set_next_existing(self, view):
1278+ """Set the next id and fire signal."""
1279+ view.next = self._existing_account_id
1280+ view.wizard().next()
1281+
1282+ def _set_next_new(self, view):
1283+ """Set the next id and fire signal."""
1284+ view.next = self._new_account_id
1285+ view.wizard().next()
1286+
1287+
1288+class CurrentUserController(object):
1289+ """Controller used in the view that is used to allow the signin."""
1290+
1291+ def __init__(self, title=''):
1292+ """Create a new instance."""
1293+ self._title = title
1294+
1295+ def _set_translated_strings(self, view):
1296+ """Set the translated strings."""
1297+ logger.debug('Setting tranlated strings.')
1298+ view.email_edit.setPlaceholderText(EMAIL1_ENTRY)
1299+ view.password_edit.setPlaceholderText(PASSWORD1_ENTRY)
1300+ view.forgot_password_label.setText(FORGOTTEN_PASSWORD_BUTTON)
1301+ view.sign_in_button.setText(SIGN_IN_BUTTON)
1302+
1303+ # use an ugly name just so have a simlar api as found in PyQt
1304+ #pylint: disable=C0103
1305+ def setupUi(self, view):
1306+ """Setup the view."""
1307+ view.setTitle(self._title)
1308+ self._set_translated_strings(view)
1309+ #pylint: enable=C0103
1310+
1311+
1312+class SetUpAccountController(object):
1313+ """Conroller for the setup account view."""
1314+
1315+ def __init__(self, tos_id=0, validation_id=1, app_name='',
1316+ help_message=''):
1317+ """Create a new instance."""
1318+ self._tos_id = tos_id
1319+ self._validation_id = validation_id
1320+ self._app_name = app_name
1321+ self._help_message = help_message
1322+
1323+ def _set_translated_strings(self, view):
1324+ """Set the different gettext translated strings."""
1325+ logger.debug('Setting tranlated strings.')
1326+ # set the translated string
1327+ view.name_edit.setPlaceholderText(NAME_ENTRY)
1328+ view.last_name_edit.setPlaceholderText(SURNAME_ENTRY)
1329+ view.email_edit.setPlaceholderText(EMAIL1_ENTRY)
1330+ view.confirm_email_edit.setPlaceholderText(EMAIL2_ENTRY)
1331+ view.password_edit.setPlaceholderText(PASSWORD1_ENTRY)
1332+ view.confirm_password_edit.setPlaceholderText(PASSWORD2_ENTRY)
1333+ view.password_info_label.setText(PASSWORD_HELP)
1334+ view.captcha_solution_edit.setPlaceholderText(CAPTCHA_SOLUTION_ENTRY)
1335+ view.terms_and_conditions_check_box.setText(YES_TO_TC)
1336+ view.terms_and_conditions_button.setText(TC_BUTTON)
1337+ view.set_up_button.setText(SET_UP_ACCOUNT_BUTTON)
1338+
1339+ def _set_line_edits_validations(self, view):
1340+ """Set the validations to be performed on the edits."""
1341+ view.set_line_edit_validation_rule(view.email_edit,
1342+ self.is_correct_email)
1343+ # set the validation rule for the email confirmation
1344+ view.set_line_edit_validation_rule(view.confirm_email_edit,
1345+ lambda x: self.is_correct_email_confirmation(x, view))
1346+ # connect the changed text of the password to trigger a changed text
1347+ # in the confirm so that the validation is redone
1348+ view.email_edit.textChanged.connect(
1349+ view.confirm_email_edit.textChanged.emit)
1350+ view.set_line_edit_validation_rule(view.password_edit,
1351+ is_min_required_password)
1352+ view.set_line_edit_validation_rule(view.confirm_password_edit,
1353+ lambda x: self.is_correct_password_confirmation(x, view))
1354+ # same as the above case, lets connect a signal to a signal
1355+ view.password_edit.textChanged.connect(
1356+ view.confirm_password_edit.textChanged.emit)
1357+
1358+ def _connect_ui_elements(self, view):
1359+ """Set the connection of signals."""
1360+ view.terms_and_conditions_button.clicked.connect(
1361+ lambda: self.set_next_tos(view))
1362+ view.set_up_button.clicked.connect(lambda: self.set_next_validation(
1363+ view))
1364+ view.password_edit.textChanged.connect(
1365+ lambda x: self.update_password_strength(x, view))
1366+ view.terms_and_conditions_check_box.stateChanged.connect(
1367+ view.set_up_button.setEnabled)
1368+
1369+ def _set_titles(self, view):
1370+ """Set the diff titles of the view."""
1371+ view.setTitle(JOIN_HEADER_LABEL % {'app_name': self._app_name})
1372+ view.setSubTitle(self._help_message)
1373+
1374+ def set_next_tos(self, view):
1375+ """Set the tos page as the next one."""
1376+ view.next = self._tos_id
1377+ view.wizard().next()
1378+
1379+ def set_next_validation(self, view):
1380+ """Set the validation as the next page."""
1381+ view.next = self._validation_id
1382+ view.wizard().next()
1383+
1384+ def update_password_strength(self, password, view):
1385+ """Callback used to update the password strenght UI code."""
1386+ # get the strengh and then according to it color the frames
1387+ strengh = get_password_strength(password)
1388+ logger.info('Password strengh is %s', strengh)
1389+ view.set_strenght_level(strengh, password)
1390+
1391+ def is_correct_email(self, email_address):
1392+ """Return if the email is correct."""
1393+ return '@' in email_address
1394+
1395+ def is_correct_email_confirmation(self, email_address, view):
1396+ """Return that the email is the same."""
1397+ return view.email_edit.text() == email_address
1398+
1399+ def is_correct_password_confirmation(self, password, view):
1400+ """Return that the passwords are correct."""
1401+ return view.password_edit.text() == password
1402+
1403+ #pylint: disable=C0103
1404+ def setupUi(self, view):
1405+ """Setup the view."""
1406+ self._set_titles(view)
1407+ self._set_translated_strings(view)
1408+ self._set_line_edits_validations(view)
1409+ self._connect_ui_elements(view)
1410+ #pylint: enable=C0103
1411+
1412+
1413+class TosController(object):
1414+ """Controller used for the tos page."""
1415+
1416+ def __init__(self, title='', subtitle='', tos_url='http://www.ubuntu.com'):
1417+ """Create a new instance."""
1418+ self._title = title
1419+ self._subtitle = subtitle
1420+ self._tos_url = tos_url
1421+
1422+ #pylint: disable=C0103
1423+ def setupUi(self, view):
1424+ """Set up the ui."""
1425+ view.setTitle(self._title)
1426+ view.setSubTitle(self._subtitle)
1427+ # load the tos page
1428+ view.webkit.load(QUrl(self._tos_url))
1429+ #pylint: enable=C0103
1430+
1431+
1432+class EmailVerificationController(object):
1433+ """Controller used for the verification page."""
1434+
1435+ def _set_translated_strings(self, view):
1436+ """Set the trnaslated strings."""
1437+ view.verification_code_edit.setPlaceholderText(VERIFY_EMAIL_TITLE)
1438+
1439+ def _connect_ui_elements(self, view):
1440+ """Set the connection of signals."""
1441+ view.next_button.clicked.connect(lambda: self.next_page(view))
1442+
1443+ def _set_titles(self, view):
1444+ """Set the different titles."""
1445+ view.setTitle(VERIFY_EMAIL_TITLE)
1446+ view.setSubTitle(VERIFY_EMAIL_CONTENT)
1447+
1448+ #pylint: disable=C0103
1449+ def setupUi(self, view):
1450+ """Setup the view."""
1451+ self._set_titles(view)
1452+ self._set_translated_strings(view)
1453+ self._connect_ui_elements(view)
1454+ #pylint: enable=C0103
1455+
1456+ def next_page(self, view):
1457+ """Call the next action."""
1458+ view.wizard().next()
1459
1460=== modified file 'ubuntu_sso/qt/gui.py'
1461--- ubuntu_sso/qt/gui.py 2011-03-12 01:22:22 +0000
1462+++ ubuntu_sso/qt/gui.py 2011-04-05 13:47:53 +0000
1463@@ -16,6 +16,444 @@
1464 # with this program. If not, see <http://www.gnu.org/licenses/>.
1465 """Qt implementation of the UI."""
1466
1467+from PyQt4 import Qt
1468+from PyQt4.QtGui import (
1469+ QApplication,
1470+ QColor,
1471+ QCursor,
1472+ QHBoxLayout,
1473+ QPalette,
1474+ QPixmap,
1475+ QPushButton,
1476+ QStyle,
1477+ QWizard,
1478+ QWizardPage,
1479+ QGraphicsScene)
1480+
1481+from ubuntu_sso.logger import setup_logging
1482+# pylint: disable=F0401,E0611
1483+from ubuntu_sso.qt.choose_sign_in_ui import Ui_ChooseSignInPage
1484+from ubuntu_sso.qt.current_user_sign_in_ui import Ui_CurrentUserSignInPage
1485+from ubuntu_sso.qt.email_verification_ui import Ui_EmailVerificationPage
1486+from ubuntu_sso.qt.setup_account_ui import Ui_SetUpAccountPage
1487+from ubuntu_sso.qt.terms_and_conditions_ui import Ui_TosPage
1488+# pylint: enable=F0401,E0611
1489+from ubuntu_sso.qt.controllers import (
1490+ ChooseSignInController,
1491+ CurrentUserController,
1492+ EmailVerificationController,
1493+ SetUpAccountController,
1494+ TosController)
1495+
1496+
1497+logger = setup_logging('ubuntu_sso.gui')
1498+
1499+# colors used to define the password stenght
1500+WEAK_COLOR = QColor(220, 20, 60)
1501+MEDIUN_COLOR = QColor(255, 215, 0)
1502+STRONG_COLOR = QColor(50, 205, 50)
1503+
1504+
1505+class ChooseSignInPage(QWizardPage):
1506+ """Widget that allows the user to choose how to sign in."""
1507+
1508+ def __init__(self, ui, controller, parent=None):
1509+ """Create a new widget to be used."""
1510+ QWizardPage.__init__(self, parent)
1511+ self.ui = ui
1512+ self.controller = controller
1513+ ui.setupUi(self)
1514+ controller.setupUi(self)
1515+ self.next = -1
1516+
1517+ # pylint: disable=C0103
1518+ def nextId(self):
1519+ """Provide the next id."""
1520+ return self.next
1521+ # pylint: enable=C0103
1522+
1523+ # allow to access to the different useful children
1524+ @property
1525+ def existing_account_button(self):
1526+ """Return the button used to sign in using an existing account."""
1527+ return self.ui.existing_account_button
1528+
1529+ @property
1530+ def new_account_button(self):
1531+ """Return the button used to sign in with a new account."""
1532+ return self.ui.setup_account_button
1533+
1534+
1535+class CurrentUserSignInPage(QWizardPage):
1536+ """Widget that allows to get the data of user to sign in."""
1537+
1538+ def __init__(self, ui, controller, parent=None):
1539+ """Create a new widget to be used."""
1540+ QWizardPage.__init__(self, parent)
1541+ self.ui = ui
1542+ self.controller = controller
1543+ self.ui.setupUi(self)
1544+ self.controller.setupUi(self)
1545+
1546+ # allow to access to the different useful data
1547+ @property
1548+ def email(self):
1549+ """Return the email data in the edit field."""
1550+ return str(self.ui.email_edit.text())
1551+
1552+ @property
1553+ def email_edit(self):
1554+ """Return the email edit that is used in the view."""
1555+ return self.ui.email_edit
1556+
1557+ @property
1558+ def password(self):
1559+ """Return the password data in the edit field."""
1560+ return str(self.ui.password_edit.text())
1561+
1562+ @property
1563+ def password_edit(self):
1564+ """Return the password edit used in the view."""
1565+ return self.ui.password_edit
1566+
1567+ @property
1568+ def forgot_password_label(self):
1569+ """Return the forgot password label."""
1570+ return self.ui.forgot_label
1571+
1572+ @property
1573+ def sign_in_button(self):
1574+ """Return the sign in button."""
1575+ return self.ui.sign_in_button
1576+
1577+
1578+class EmailVerificationPage(QWizardPage):
1579+ """Widget used to input the email verification code."""
1580+
1581+ def __init__(self, ui, controller, parent=None):
1582+ """Create a new widget to be used."""
1583+ QWizardPage.__init__(self, parent)
1584+ self.ui = ui
1585+ self.ui.setupUi(self)
1586+ self.controller = controller
1587+ self.controller.setupUi(self)
1588+
1589+ @property
1590+ def verification_code(self):
1591+ """Return the content of the verification code edit."""
1592+ return str(self.ui.verification_code_edit)
1593+
1594+ @property
1595+ def verification_code_edit(self):
1596+ """Return the edit used for the verification code."""
1597+ return self.ui.verification_code_edit
1598+
1599+ @property
1600+ def next_button(self):
1601+ """Return the button that move to the next stage."""
1602+ return self.ui.next_button
1603+
1604+
1605+class TosPage(QWizardPage):
1606+ """Widget used to show the tos."""
1607+
1608+ def __init__(self, ui, controller, parent=None):
1609+ """Create a new instance."""
1610+ QWizardPage.__init__(self, parent)
1611+ self.ui = ui
1612+ self.ui.setupUi(self)
1613+ self.controller = controller
1614+ self.controller.setupUi(self)
1615+
1616+ # pylint: disable=C0103
1617+ def nextId(self):
1618+ """Return the next page id."""
1619+ return -1
1620+ # pylint: enable=C0103
1621+
1622+ @property
1623+ def webkit(self):
1624+ """Return the webkit widget used to load the terms."""
1625+ return self.ui.terms_webkit
1626+
1627+
1628+class EnhancedLineEdit(object):
1629+ """Represents an enhanced lineedit.
1630+
1631+ This class works on an already added lineedit to the widget so
1632+ that we are just adding extra items to it.
1633+ """
1634+
1635+ def __init__(self, line_edit, valid_cb=lambda x: False):
1636+ """Create an instance."""
1637+ self._line_edit = line_edit
1638+ layout = QHBoxLayout(self._line_edit)
1639+ layout.setMargin(0)
1640+ self._line_edit.setLayout(layout)
1641+ self.valid_cb = valid_cb
1642+ layout.addStretch()
1643+ self.clear_button = QPushButton(self._line_edit)
1644+ layout.addWidget(self.clear_button)
1645+ self.clear_button.setMinimumSize(16, 16)
1646+ self.clear_button.setVisible(False)
1647+ self.clear_button.setFlat(True)
1648+ self.clear_button.setCursor(QCursor(0))
1649+ self.clear_button.setIcon(QApplication.style().standardIcon(
1650+ QStyle.SP_MessageBoxWarning))
1651+ # connect the change of text to the caption that will check if the
1652+ # text is valid and if the icon should be shown.
1653+ self._line_edit.textChanged.connect(self.show_button)
1654+
1655+ def show_button(self, string):
1656+ """Decide if we show the button or not."""
1657+ if not self.valid_cb(string):
1658+ self.clear_button.setVisible(True)
1659+ else:
1660+ self.clear_button.setVisible(False)
1661+
1662+
1663+class SetupAccountPage(QWizardPage):
1664+ """Widget used to create a new account."""
1665+
1666+ def __init__(self, ui, controller, parent=None):
1667+ """Create a new widget to be used."""
1668+ QWizardPage.__init__(self, parent)
1669+ self._enhanced_edits = {}
1670+ self.ui = ui
1671+ self.ui.setupUi(self)
1672+ # palettes that will be used to set the colors of the password strenght
1673+ original_palette = self.ui.strenght_frame.palette()
1674+ self._original_color = original_palette.background().color()
1675+ self.controller = controller
1676+ self.controller.setupUi(self)
1677+ self.next = -1
1678+ # create the scene to be used to show the captcha
1679+ self.image = None
1680+ self.image_file = None
1681+ self.scene = QGraphicsScene(self.ui.captcha_view)
1682+
1683+ def set_strenght_level(self, level, password):
1684+ """Set the strenght level colors."""
1685+ if password != '':
1686+ if level <= 1:
1687+ # low password
1688+ self._set_frame_color(self.ui.weak_frame, WEAK_COLOR)
1689+ self._set_frame_color(self.ui.medium_frame,
1690+ self._original_color)
1691+ self._set_frame_color(self.ui.strong_frame,
1692+ self._original_color)
1693+ elif level <= 3:
1694+ # medium password
1695+ self._set_frame_color(self.ui.weak_frame, MEDIUM_COLOR)
1696+ self._set_frame_color(self.ui.medium_frame, MEDIUM_COLOR)
1697+ self._set_frame_color(self.ui.strong_frame,
1698+ self._original_color)
1699+ else:
1700+ # nice!
1701+ self._set_frame_color(self.ui.weak_frame, STRONG_COLOR)
1702+ self._set_frame_color(self.ui.medium_frame, STRONG_COLOR)
1703+ self._set_frame_color(self.ui.strong_frame, STRONG_COLOR)
1704+ else:
1705+ # set it to the minimum
1706+ self._set_frame_color(self.ui.weak_frame, self._original_color)
1707+ self._set_frame_color(self.ui.medium_frame, self._original_color)
1708+ self._set_frame_color(self.ui.strong_frame, self._original_color)
1709+
1710+ def _set_frame_color(self, frame, color):
1711+ """Set the color of a frame to indicated a strenght."""
1712+ # change the color background for the given frame
1713+ palette = frame.palette()
1714+ palette.setColor(QPalette.Background, color)
1715+ frame.setPalette(palette)
1716+ frame.setAutoFillBackground(True)
1717+
1718+ # pylint: disable=C0103
1719+ def nextId(self):
1720+ """Return the next page id."""
1721+ return self.next
1722+ # pylint: enable=C0103
1723+
1724+ def set_line_edit_validation_rule(self, edit, cb):
1725+ """Set a new enhanced edit so that we can show an icon."""
1726+ if edit in self._enhanced_edits:
1727+ self._enhanced_edits[edit].valid_cb = cb
1728+ else:
1729+ # create a new enhanced edit
1730+ enhanced_edit = EnhancedLineEdit(edit, cb)
1731+ self._enhanced_edits[edit] = enhanced_edit
1732+
1733+ @property
1734+ def name(self):
1735+ """Return the name input."""
1736+ return str(self.ui.first_name_edit.text())
1737+
1738+ @property
1739+ def name_edit(self):
1740+ """Return the edit used for the name."""
1741+ return self.ui.first_name_edit
1742+
1743+ @property
1744+ def last_name(self):
1745+ """Return the last name input."""
1746+ return str(self.ui.last_name_edit.text())
1747+
1748+ @property
1749+ def last_name_edit(self):
1750+ """Return the edit used for the last name."""
1751+ return self.ui.last_name_edit
1752+
1753+ @property
1754+ def email(self):
1755+ """Return the email input."""
1756+ return str(self.ui.email_edit.text())
1757+
1758+ @property
1759+ def email_edit(self):
1760+ """Return the edit used for the email."""
1761+ return self.ui.email_edit
1762+
1763+ @property
1764+ def retyped_email(self):
1765+ """Return the retyped email."""
1766+ return str(self.ui.confirm_email_edit.text())
1767+
1768+ @property
1769+ def confirm_email_edit(self):
1770+ """Return the edit used for the retype of the email."""
1771+ return self.ui.confirm_email_edit
1772+
1773+ @property
1774+ def password_info_label(self):
1775+ """Return the password used to show the info of the label."""
1776+ return self.ui.password_info_label
1777+
1778+ @property
1779+ def password(self):
1780+ """Return the password data."""
1781+ return str(self.ui.password_edit.text())
1782+
1783+ @property
1784+ def password_edit(self):
1785+ """Return the edit used for the password."""
1786+ return self.ui.password_edit
1787+
1788+ @property
1789+ def retyped_password(self):
1790+ """Return the retyped password."""
1791+ return str(self.ui.confirm_password_edit.text())
1792+
1793+ @property
1794+ def confirm_password_edit(self):
1795+ """Return the edit used to confirm the password."""
1796+ return self.ui.confirm_password_edit
1797+
1798+ @property
1799+ def captcha_solution(self):
1800+ """Return the provided captcha solution."""
1801+ return str(self.ui.captcha_solution_edit.text())
1802+
1803+ @property
1804+ def captcha_solution_edit(self):
1805+ """Return the edit used for the captcha solution."""
1806+ return self.ui.captcha_solution_edit
1807+
1808+ def get_captcha_image(self):
1809+ """Return the path to the captcha image."""
1810+ return self.image_file
1811+
1812+ def set_captcha_image(self, file_path):
1813+ """Set the new image of the captcha."""
1814+ if self.image:
1815+ self.scene.removeItem(self.image)
1816+ self.image_file = file_path
1817+ pix = QPixmap(self.image_file)
1818+ self.image = self.scene.addPixmap(pix)
1819+
1820+ captcha_image = property(get_captcha_image, set_captcha_image)
1821+
1822+ @property
1823+ def terms_and_conditions_agreed(self):
1824+ """Return if the user agreed the terms."""
1825+ return self.ui.terms_checkbox.isChecked()
1826+
1827+ @property
1828+ def terms_and_conditions_check_box(self):
1829+ """Return the terms and codition item."""
1830+ return self.ui.terms_checkbox
1831+
1832+ @property
1833+ def terms_and_conditions_button(self):
1834+ """Return the terms and conditions button."""
1835+ return self.ui.terms_button
1836+
1837+ @property
1838+ def set_up_button(self):
1839+ """Return the set up button."""
1840+ return self.ui.set_up_button
1841+
1842+
1843+class UbuntuSSOWizard(QWizard):
1844+ """Wizard used to create or use sso."""
1845+
1846+ def __init__(self, parent=None, app_name='', tos_url='', help_text=''):
1847+ """Create a new wizard."""
1848+ QWizard.__init__(self, parent)
1849+ # set the diff pages of the QWizard
1850+ self.sign_in_controller = ChooseSignInController(title='Sign In',
1851+ existing_account_id=4,
1852+ new_account_id=1)
1853+ self.sign_in_page = ChooseSignInPage(Ui_ChooseSignInPage(),
1854+ self.sign_in_controller,
1855+ parent=self)
1856+ self.setup_controller = SetUpAccountController(tos_id=2,
1857+ validation_id=3,
1858+ app_name=app_name,
1859+ help_message='')
1860+ self.setup_account = SetupAccountPage(Ui_SetUpAccountPage(),
1861+ self.setup_controller,
1862+ parent=self)
1863+ self.tos = TosPage(Ui_TosPage(), TosController())
1864+ self.email_verification = EmailVerificationPage(
1865+ Ui_EmailVerificationPage(),
1866+ EmailVerificationController())
1867+ self.current_user_controller = CurrentUserController(title='Sign in')
1868+ self.current_user = CurrentUserSignInPage(Ui_CurrentUserSignInPage(),
1869+ self.current_user_controller,
1870+ parent=self)
1871+ for page in [self.sign_in_page, self.setup_account, self.tos,
1872+ self.email_verification, self.current_user]:
1873+ self.addPage(page)
1874+ # set the buttons layout to only have cancel and back since the next
1875+ # buttons are the ones used in the diff pages.
1876+ buttons_layout = []
1877+ buttons_layout.append(QWizard.Stretch)
1878+ buttons_layout.append(QWizard.BackButton)
1879+ buttons_layout.append(QWizard.CancelButton)
1880+ self.setButtonLayout(buttons_layout)
1881+ self.setWindowTitle(app_name)
1882+
1883+
1884+class UbuntuSSOWizardController(object):
1885+ """Performs the logic of the sso wizard."""
1886+
1887+ def __init__(self, app_name, tc_url='', help_text='',
1888+ window_id=0, login_only=False):
1889+ """Create a new instance."""
1890+ # create a new wizard and show it
1891+ self.wizard = None
1892+
1893
1894 class UbuntuSSOClientGUI(object):
1895 """Ubuntu single sign-on GUI."""
1896+
1897+if __name__ == '__main__':
1898+ # pylint: disable=C0103
1899+ # show the ui
1900+ import sys
1901+
1902+ app = Qt.QApplication(sys.argv)
1903+
1904+ wizard = UbuntuSSOWizard()
1905+ wizard.show()
1906+ # Now we can start it.
1907+ app.exec_()
1908
1909=== added directory 'ubuntu_sso/qt/tests'
1910=== added file 'ubuntu_sso/qt/tests/__init__.py'
1911--- ubuntu_sso/qt/tests/__init__.py 1970-01-01 00:00:00 +0000
1912+++ ubuntu_sso/qt/tests/__init__.py 2011-04-05 13:47:53 +0000
1913@@ -0,0 +1,1 @@
1914+"""Test the Ui code."""
1915
1916=== added file 'ubuntu_sso/qt/tests/test_controllers.py'
1917--- ubuntu_sso/qt/tests/test_controllers.py 1970-01-01 00:00:00 +0000
1918+++ ubuntu_sso/qt/tests/test_controllers.py 2011-04-05 13:47:53 +0000
1919@@ -0,0 +1,318 @@
1920+# -*- coding: utf-8 -*-
1921+# Author: Manuel de la Pena <manuel@canonical.com>
1922+#
1923+# Copyright 2011 Canonical Ltd.
1924+#
1925+# This program is free software: you can redistribute it and/or modify it
1926+# under the terms of the GNU General Public License version 3, as published
1927+# by the Free Software Foundation.
1928+#
1929+# This program is distributed in the hope that it will be useful, but
1930+# WITHOUT ANY WARRANTY; without even the implied warranties of
1931+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1932+# PURPOSE. See the GNU General Public License for more details.
1933+#
1934+# You should have received a copy of the GNU General Public License along
1935+# with this program. If not, see <http://www.gnu.org/licenses/>.
1936+"""Test the ui controllers."""
1937+
1938+from mocker import ANY, MATCH, MockerTestCase
1939+
1940+from ubuntu_sso.qt.controllers import (
1941+ ChooseSignInController,
1942+ CurrentUserController,
1943+ EmailVerificationController,
1944+ SetUpAccountController,
1945+ TosController)
1946+from ubuntu_sso.utils.ui import (
1947+ CAPTCHA_SOLUTION_ENTRY,
1948+ EMAIL1_ENTRY,
1949+ EMAIL2_ENTRY,
1950+ EXISTING_ACCOUNT_CHOICE_BUTTON,
1951+ FORGOTTEN_PASSWORD_BUTTON,
1952+ JOIN_HEADER_LABEL,
1953+ NAME_ENTRY,
1954+ PASSWORD1_ENTRY,
1955+ PASSWORD2_ENTRY,
1956+ PASSWORD_HELP,
1957+ SET_UP_ACCOUNT_CHOICE_BUTTON,
1958+ SET_UP_ACCOUNT_BUTTON,
1959+ SIGN_IN_BUTTON,
1960+ SURNAME_ENTRY,
1961+ TC_BUTTON,
1962+ VERIFY_EMAIL_TITLE,
1963+ VERIFY_EMAIL_CONTENT,
1964+ YES_TO_TC,
1965+ is_min_required_password)
1966+
1967+#ignore the comon mocker issues with lint
1968+# pylint: disable=W0212,W0104
1969+
1970+
1971+class ChooseSignInControllerTestCase(MockerTestCase):
1972+ """Test the choose sign in controller."""
1973+
1974+ def setUp(self):
1975+ """Set tests."""
1976+ super(ChooseSignInControllerTestCase, self).setUp()
1977+ self.view = self.mocker.mock()
1978+ self.controller = ChooseSignInController()
1979+
1980+ def test_set_up_translated_strings(self):
1981+ """Ensure that the translations are used."""
1982+ self.view.existing_account_button.setText(
1983+ EXISTING_ACCOUNT_CHOICE_BUTTON)
1984+ self.view.new_account_button.setText(SET_UP_ACCOUNT_CHOICE_BUTTON)
1985+ self.mocker.replay()
1986+ self.controller._set_up_translated_strings(self.view)
1987+
1988+ def test_connect_buttons(self):
1989+ """Ensure that all the buttons are correcly connected."""
1990+ self.view.existing_account_button.clicked.connect(MATCH(callable))
1991+ self.view.new_account_button.clicked.connect(MATCH(callable))
1992+ self.mocker.replay()
1993+ self.controller._connect_buttons(self.view)
1994+
1995+ def test_set_next_existing(self):
1996+ """Test the execution of the callback."""
1997+ self.view.next = self.controller._existing_account_id
1998+ self.view.wizard().next()
1999+ self.mocker.replay()
2000+ self.controller._set_next_existing(self.view)
2001+
2002+ def test_set_next_new(self):
2003+ """Test the execution of the callback."""
2004+ self.view.next = self.controller._new_account_id
2005+ self.view.wizard().next()
2006+ self.mocker.replay()
2007+ self.controller._set_next_new(self.view)
2008+
2009+
2010+class CurrentUserControllerTestCase(MockerTestCase):
2011+ """Test the current user controller."""
2012+
2013+ def setUp(self):
2014+ """Setup tests."""
2015+ super(CurrentUserControllerTestCase, self).setUp()
2016+ self.view = self.mocker.mock()
2017+ self.controller = CurrentUserController(title='the title')
2018+
2019+ def test_setup_ui(self):
2020+ """test that the ui is correctly set up."""
2021+ self.view.setTitle(self.controller._title)
2022+ self.view.email_edit.setPlaceholderText(EMAIL1_ENTRY)
2023+ self.view.password_edit.setPlaceholderText(PASSWORD1_ENTRY)
2024+ self.view.forgot_password_label.setText(FORGOTTEN_PASSWORD_BUTTON)
2025+ self.view.sign_in_button.setText(SIGN_IN_BUTTON)
2026+ self.mocker.replay()
2027+ self.controller.setupUi(self.view)
2028+
2029+
2030+class SetUpAccountControllerTestCase(MockerTestCase):
2031+ """test the controller used to setup a new account."""
2032+
2033+ def setUp(self):
2034+ """Set the different tests."""
2035+ super(SetUpAccountControllerTestCase, self).setUp()
2036+ self.view = self.mocker.mock()
2037+ self.get_password_strength = self.mocker.replace(
2038+ 'ubuntu_sso.utils.ui.get_password_strength')
2039+ self.app_name = 'test'
2040+ self.help = 'help'
2041+ self.controller = SetUpAccountController(app_name=self.app_name,
2042+ help_message=self.help)
2043+
2044+ def test_set_translated_strings(self):
2045+ """Ensure all the strings are set."""
2046+ self.view.name_edit.setPlaceholderText(NAME_ENTRY)
2047+ self.view.last_name_edit.setPlaceholderText(SURNAME_ENTRY)
2048+ self.view.email_edit.setPlaceholderText(EMAIL1_ENTRY)
2049+ self.view.confirm_email_edit.setPlaceholderText(EMAIL2_ENTRY)
2050+ self.view.password_edit.setPlaceholderText(PASSWORD1_ENTRY)
2051+ self.view.confirm_password_edit.setPlaceholderText(PASSWORD2_ENTRY)
2052+ self.view.password_info_label.setText(PASSWORD_HELP)
2053+ self.view.captcha_solution_edit.setPlaceholderText(
2054+ CAPTCHA_SOLUTION_ENTRY)
2055+ self.view.terms_and_conditions_check_box.setText(YES_TO_TC)
2056+ self.view.terms_and_conditions_button.setText(TC_BUTTON)
2057+ self.view.set_up_button.setText(SET_UP_ACCOUNT_BUTTON)
2058+ self.mocker.replay()
2059+ self.controller._set_translated_strings(self.view)
2060+
2061+ def test_set_titles(self):
2062+ """Test how the different titles are set."""
2063+ self.view.setTitle(JOIN_HEADER_LABEL % {'app_name': self.app_name})
2064+ self.view.setSubTitle(self.help)
2065+ self.mocker.replay()
2066+ self.controller._set_titles(self.view)
2067+
2068+ def test_connect_ui_elements(self):
2069+ """Test that the ui elements are correctly connect."""
2070+ self.view.terms_and_conditions_button.clicked.connect(MATCH(callable))
2071+ self.view.set_up_button.clicked.connect(MATCH(callable))
2072+ self.view.password_edit.textChanged.connect(MATCH(callable))
2073+ self.view.set_up_button.setEnabled
2074+ self.mocker.result(lambda:None)
2075+ self.view.terms_and_conditions_check_box.stateChanged.connect(
2076+ MATCH(callable))
2077+ self.mocker.replay()
2078+ self.controller._connect_ui_elements(self.view)
2079+
2080+ def test_is_correct_password_confirmation_false(self):
2081+ """Test when the password is not correct."""
2082+ password = 'test'
2083+ self.view.password_edit.text()
2084+ self.mocker.result('other')
2085+ self.mocker.replay()
2086+ self.assertFalse(
2087+ self.controller.is_correct_password_confirmation(password,
2088+ self.view))
2089+
2090+ def test_is_correct_password_confirmation_true(self):
2091+ """Test when the password is correct."""
2092+ password = 'test'
2093+ self.view.password_edit.text()
2094+ self.mocker.result(password)
2095+ self.mocker.replay()
2096+ self.assertTrue(
2097+ self.controller.is_correct_password_confirmation(password,
2098+ self.view))
2099+
2100+ def test_is_correct_email_confirmation_false(self):
2101+ """Test when the emails are not the same."""
2102+ email_address = 'address'
2103+ self.view.email_edit.text()
2104+ self.mocker.result('other')
2105+ self.mocker.replay()
2106+ self.assertFalse(
2107+ self.controller.is_correct_email_confirmation(email_address,
2108+ self.view))
2109+
2110+ def test_is_correct_email_confirmation_true(self):
2111+ """Test when the emails are the same."""
2112+ email_address = 'address'
2113+ self.view.email_edit.text()
2114+ self.mocker.result(email_address)
2115+ self.mocker.replay()
2116+ self.assertTrue(
2117+ self.controller.is_correct_email_confirmation(email_address,
2118+ self.view))
2119+
2120+ def test_is_correct_email_true(self):
2121+ """Test when the email is correct."""
2122+ email = 'manuel@canonical.com'
2123+ self.mocker.replay()
2124+ self.assertTrue(self.controller.is_correct_email(email))
2125+
2126+ def test_is_correct_email_false(self):
2127+ """Test when the email is not correct."""
2128+ email = 'manuelcanonical.com'
2129+ self.mocker.replay()
2130+ self.assertFalse(self.controller.is_correct_email(email))
2131+
2132+ def test_set_next_tos(self):
2133+ """Test the callback."""
2134+ self.view.next = self.controller._tos_id
2135+ self.view.wizard().next()
2136+ self.mocker.replay()
2137+ self.controller.set_next_tos(self.view)
2138+
2139+ def test_set_next_validation(self):
2140+ """Test the callback."""
2141+ self.view.next = self.controller._validation_id
2142+ self.view.wizard().next()
2143+ self.mocker.replay()
2144+ self.controller.set_next_validation(self.view)
2145+
2146+ def test_update_password_strength(self):
2147+ """Test the callback."""
2148+ password = 'test'
2149+ strength = 4
2150+ self.get_password_strength(password)
2151+ self.mocker.result(strength)
2152+ self.view.set_strenght_level(strength, password)
2153+ self.mocker.replay()
2154+ self.controller.update_password_strength(password, self.view)
2155+
2156+ def test_set_line_edits_validations(self):
2157+ """Set the validations to be performed on the edits."""
2158+ self.view.email_edit
2159+ self.mocker.result(self.view)
2160+ self.view.set_line_edit_validation_rule(self.view,
2161+ self.controller.is_correct_email)
2162+ self.view.confirm_email_edit
2163+ self.mocker.result(self.view)
2164+ self.view.set_line_edit_validation_rule(self.view, MATCH(callable))
2165+ self.view.confirm_email_edit.textChanged.emit
2166+ self.mocker.result(lambda: None)
2167+ self.view.email_edit.textChanged.connect(MATCH(callable))
2168+ self.view.password_edit
2169+ self.mocker.result(self.view)
2170+ self.view.set_line_edit_validation_rule(self.view,
2171+ is_min_required_password)
2172+ self.view.confirm_password_edit
2173+ self.mocker.result(self.view)
2174+ self.view.set_line_edit_validation_rule(self.view, MATCH(callable))
2175+ self.view.confirm_password_edit.textChanged.emit
2176+ self.mocker.result(lambda: None)
2177+ self.view.password_edit.textChanged.connect(MATCH(callable))
2178+ self.mocker.replay()
2179+ self.controller._set_line_edits_validations(self.view)
2180+
2181+
2182+class TosControllerTestCase(MockerTestCase):
2183+ """Test the tos controller."""
2184+
2185+ def setUp(self):
2186+ """Set the tests."""
2187+ super(TosControllerTestCase, self).setUp()
2188+ self.view = self.mocker.mock()
2189+ self.title = 'title'
2190+ self.subtitle = 'sub'
2191+ self.url = 'url'
2192+ self.controller = TosController(title=self.title,
2193+ subtitle=self.subtitle,
2194+ tos_url=self.url)
2195+
2196+ def test_setup_ui(self):
2197+ """Test the set up of the ui."""
2198+ self.view.setTitle(self.title)
2199+ self.view.setSubTitle(self.subtitle)
2200+ self.view.webkit.load(ANY)
2201+ self.mocker.replay()
2202+ self.controller.setupUi(self.view)
2203+
2204+
2205+class EmailVerificationControllerTestCase(MockerTestCase):
2206+ """Test the controller."""
2207+
2208+ def setUp(self):
2209+ """Set tests."""
2210+ super(EmailVerificationControllerTestCase, self).setUp()
2211+ self.view = self.mocker.mock()
2212+ self.controller = EmailVerificationController()
2213+
2214+ def test_set_translated_strings(self):
2215+ """Test that strings are translated."""
2216+ self.view.verification_code_edit.setPlaceholderText(VERIFY_EMAIL_TITLE)
2217+ self.mocker.replay()
2218+ self.controller._set_translated_strings(self.view)
2219+
2220+ def test_connect_ui_elements(self):
2221+ """Set the ui connections."""
2222+ self.view.next_button.clicked.connect(MATCH(callable))
2223+ self.mocker.replay()
2224+ self.controller._connect_ui_elements(self.view)
2225+
2226+ def test_set_titles(self):
2227+ """Test that the titles are set."""
2228+ self.view.setTitle(VERIFY_EMAIL_TITLE)
2229+ self.view.setSubTitle(VERIFY_EMAIL_CONTENT)
2230+ self.mocker.replay()
2231+ self.controller._set_titles(self.view)
2232+
2233+ def test_next_page(self):
2234+ """Test the callback."""
2235+ self.view.wizard().next()
2236+ self.mocker.replay()
2237+ self.controller.next_page(self.view)
2238
2239=== added file 'ubuntu_sso/utils/tests/test_ui.py'
2240--- ubuntu_sso/utils/tests/test_ui.py 1970-01-01 00:00:00 +0000
2241+++ ubuntu_sso/utils/tests/test_ui.py 2011-04-05 13:47:53 +0000
2242@@ -0,0 +1,110 @@
2243+# -*- coding: utf-8 -*-
2244+# Author: Manuel de la Pena <manuel@canonical.com>
2245+#
2246+# Copyright 2011 Canonical Ltd.
2247+#
2248+# This program is free software: you can redistribute it and/or modify it
2249+# under the terms of the GNU General Public License version 3, as published
2250+# by the Free Software Foundation.
2251+#
2252+# This program is distributed in the hope that it will be useful, but
2253+# WITHOUT ANY WARRANTY; without even the implied warranties of
2254+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2255+# PURPOSE. See the GNU General Public License for more details.
2256+#
2257+# You should have received a copy of the GNU General Public License along
2258+# with this program. If not, see <http://www.gnu.org/licenses/>.
2259+"""Test the ui functions."""
2260+
2261+from unittest import TestCase
2262+
2263+from ubuntu_sso.utils.ui import (get_password_strength,
2264+ is_min_required_password)
2265+
2266+
2267+class GetPasswordStrengTestCase(TestCase):
2268+ """Test the function that returns the strengh of a password."""
2269+
2270+ def test_too_small_password(self):
2271+ """Test the points given to a very small password."""
2272+ password = 'abc'
2273+ self.assertEqual(1, get_password_strength(password))
2274+
2275+ def test_small_password(self):
2276+ """Test the points given to a small passwod 4 or more chars."""
2277+ password = 'testtwe'
2278+ self.assertEqual(0, get_password_strength(password))
2279+
2280+ def test_eight_chars_password(self):
2281+ """Test the points given to a normal 8 chars password."""
2282+ password = 'abcdabcd'
2283+ self.assertEqual(1, get_password_strength(password))
2284+
2285+ def test_eight_chars_and_num(self):
2286+ """Test the points given to a 8 chars password with a num."""
2287+ password = 'abcdabc8'
2288+ self.assertEqual(2, get_password_strength(password))
2289+
2290+ def test_eight_chars_low_and_cap(self):
2291+ """Test the points given to a 8 chars password with a capital."""
2292+ password = 'abcdabcD'
2293+ self.assertEqual(2, get_password_strength(password))
2294+
2295+ def test_eight_chars_low_canp_num(self):
2296+ """Test the points given to a 8 chars password with capitals & num."""
2297+ password = 'abcdab7D'
2298+ self.assertEqual(3, get_password_strength(password))
2299+
2300+ def test_eiqgh_chars_and_special(self):
2301+ """Test the points given to a 8 chars password with special chars."""
2302+ password = 'abcdabc*'
2303+ self.assertEqual(2, get_password_strength(password))
2304+
2305+ def test_long_password(self):
2306+ """Test the points goven to a long password."""
2307+ password = 'abcdabcdabcd'
2308+ self.assertEqual(2, get_password_strength(password))
2309+
2310+ def test_eleven_chars_and_num(self):
2311+ """Test the points of a loong password with a num."""
2312+ password = 'abcdabcdabcd99'
2313+ self.assertEqual(3, get_password_strength(password))
2314+
2315+ def test_eleven_chars_low_cap(self):
2316+ """Test the points of a long password with low and cap."""
2317+ password = 'abcdabcdabcdbABCD'
2318+ self.assertEqual(3, get_password_strength(password))
2319+
2320+ def test_eleven_num_low_cap(self):
2321+ """Test the points of a long password with num and diff cap."""
2322+ password = 'ABCDabcdacbd723'
2323+ self.assertEqual(4, get_password_strength(password))
2324+
2325+ def test_eleven_num_special(self):
2326+ """Test the point of a long password with a number and special char."""
2327+ password = 'abcdabcdabcd*9'
2328+ self.assertEqual(4, get_password_strength(password))
2329+
2330+
2331+class IsMinRequiredPasswordTestCase(TestCase):
2332+ """Test the fnction that returns if the password is the min required."""
2333+
2334+ def test_no_enough_chars(self):
2335+ """Test a password that does not have enough chars."""
2336+ password = 'Test8'
2337+ self.assertFalse(is_min_required_password(password))
2338+
2339+ def test_no_uppercase(self):
2340+ """Test a password that does not have an uppercase."""
2341+ password = 'longenoughtobeapassword8'
2342+ self.assertFalse(is_min_required_password(password))
2343+
2344+ def test_no_number(self):
2345+ """Test a password that does not have a number."""
2346+ password = 'longenoughtobeapassworD'
2347+ self.assertFalse(is_min_required_password(password))
2348+
2349+ def test_correct_password(self):
2350+ """Test a password that is correct."""
2351+ password = 'TodasLasPaswordPasan88'
2352+ self.assertTrue(is_min_required_password(password))
2353
2354=== modified file 'ubuntu_sso/utils/ui.py'
2355--- ubuntu_sso/utils/ui.py 2011-03-25 09:54:38 +0000
2356+++ ubuntu_sso/utils/ui.py 2011-04-05 13:47:53 +0000
2357@@ -19,6 +19,7 @@
2358 """Utils to be used by the UI modules."""
2359
2360 import os
2361+import re
2362 import xdg
2363 import gettext
2364
2365@@ -30,6 +31,69 @@
2366 gettext.textdomain('ubuntu-sso-client')
2367 _ = gettext.gettext
2368
2369+# all the text that is used in the gui
2370+CAPTCHA_SOLUTION_ENTRY = _('Type the characters above')
2371+CAPTCHA_LOAD_ERROR = _('There was a problem getting the captcha, '
2372+ 'reloading...')
2373+CONNECT_HELP_LABEL = _('To connect this computer to %(app_name)s ' \
2374+ 'enter your details below.')
2375+EMAIL1_ENTRY = _('Email address')
2376+EMAIL2_ENTRY = _('Re-type Email address')
2377+EMAIL_MISMATCH = _('The email addresses don\'t match, please double check '
2378+ 'and try entering them again.')
2379+EMAIL_INVALID = _('The email must be a valid email address.')
2380+EMAIL_TOKEN_ENTRY = _('Enter code verification here')
2381+ERROR = _('The process did not finish successfully.')
2382+EXISTING_ACCOUNT_CHOICE_BUTTON = _('Sign me in with my existing account')
2383+FIELD_REQUIRED = _('This field is required.')
2384+FORGOTTEN_PASSWORD_BUTTON = _('I\'ve forgotten my password')
2385+JOIN_HEADER_LABEL = _('Create %(app_name)s account')
2386+LOADING = _('Loading...')
2387+LOGIN_BUTTON_LABEL = _('Already have an account? Click here to sign in')
2388+LOGIN_EMAIL_ENTRY = _('Email address')
2389+LOGIN_HEADER_LABEL = _('Connect to %(app_name)s')
2390+LOGIN_PASSWORD_ENTRY = _('Password')
2391+NAME_ENTRY = _('Name')
2392+NEXT = _('Next')
2393+ONE_MOMENT_PLEASE = _('One moment please...')
2394+PASSWORD_CHANGED = _('Your password was successfully changed.')
2395+PASSWORD1_ENTRY = RESET_PASSWORD1_ENTRY = _('Password')
2396+PASSWORD2_ENTRY = RESET_PASSWORD2_ENTRY = _('Re-type Password')
2397+PASSWORD_HELP = _('The password must have a minimum of 8 characters and ' \
2398+ 'include one uppercase character and one number.')
2399+PASSWORD_MISMATCH = _('The passwords don\'t match, please double check ' \
2400+ 'and try entering them again.')
2401+PASSWORD_TOO_WEAK = _('The password is too weak.')
2402+REQUEST_PASSWORD_TOKEN_LABEL = _('To reset your %(app_name)s password,'
2403+ ' enter your email address below:')
2404+RESET_PASSWORD = _('Reset password')
2405+RESET_CODE_ENTRY = _('Reset code')
2406+RESET_EMAIL_ENTRY = _('Email address')
2407+SET_NEW_PASSWORD_LABEL = _('A password reset code has been sent to ' \
2408+ '%(email)s.\nPlease enter the code below ' \
2409+ 'along with your new password.')
2410+SET_UP_ACCOUNT_CHOICE_BUTTON = _('I don\'t have an account yet - sign me up')
2411+SET_UP_ACCOUNT_BUTTON = _('Set up Account')
2412+SIGN_IN_BUTTON = _('Sign In')
2413+SUCCESS = _('The process finished successfully. Congratulations!')
2414+SURNAME_ENTRY = _('Surname')
2415+TC_BUTTON = _('Show Terms & Conditions')
2416+TC_NOT_ACCEPTED = _('Agreeing to the Ubuntu One Terms & Conditions is ' \
2417+ 'required to subscribe.')
2418+UNKNOWN_ERROR = _('There was an error when trying to complete the ' \
2419+ 'process. Please check the information and try again.')
2420+VERIFY_EMAIL_TITLE = _('Enter verification code')
2421+VERIFY_EMAIL_CONTENT = _('Check %(email)s for an email from'
2422+ ' Ubuntu Single Sign On.'
2423+ ' This message contains a verification code.'
2424+ ' Enter the code in the field below and click OK'
2425+ ' to complete creating your %(app_name)s account')
2426+VERIFY_EMAIL_LABEL = ('<b>%s</b>\n\n' % VERIFY_EMAIL_TITLE +
2427+ VERIFY_EMAIL_CONTENT)
2428+YES_TO_TC = _('I agree with the %(app_name)s terms and conditions')
2429+YES_TO_UPDATES = _('Yes! Email me %(app_name)s tips and updates.')
2430+CAPTCHA_RELOAD_TOOLTIP = _('Reload')
2431+
2432
2433 def get_data_dir():
2434 """Build absolute path to the 'data' directory."""
2435@@ -61,3 +125,46 @@
2436 def get_data_file(*args):
2437 """Build absolute path to the path within the 'data' directory."""
2438 return os.path.join(get_data_dir(), *args)
2439+
2440+
2441+def get_password_strength(password):
2442+ """Return the strenght of the password.
2443+
2444+ This function returns the strenght of the password so that ui elements
2445+ can show the user how good his password is. The logic used is the
2446+ following:
2447+
2448+ * 1 extra point for 4 chars passwords
2449+ * 1 extra point for 8 chars passwords
2450+ * 1 extra point for more than 11 chars passwords.
2451+ * 1 extra point for passwords with at least one number.
2452+ * 1 extra point for passwords for lower and capital chars.
2453+ * 1 extra point for passwords with a special char.
2454+
2455+ A passwords starts with 0 and the extra points are added accordingly.
2456+ """
2457+ score = 0
2458+ if len(password) < 1:
2459+ return 0
2460+ if len(password) < 4:
2461+ score = 1
2462+ if len(password) >= 8:
2463+ score += 1
2464+ if len(password) >= 11:
2465+ score += 1
2466+ if re.search('\d+', password):
2467+ score += 1
2468+ if re.search('[a-z]', password) and re.search('[A-Z]', password):
2469+ score += 1
2470+ if re.search('.[!,@,#,$,%,^,&,*,?,_,~,-,£,(,)]', password):
2471+ score += 1
2472+ return score
2473+
2474+
2475+def is_min_required_password(password):
2476+ """Return if the password meets the minimum requirements."""
2477+ if (len(password) < 8 or
2478+ re.search('[A-Z]', password) is None or
2479+ re.search('\d+', password) is None):
2480+ return False
2481+ return True

Subscribers

People subscribed via source and target branches