Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Web / UI / WebControls / PasswordRecovery.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="PasswordRecovery.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 namespace System.Web.UI.WebControls {
8
9     using System.Collections;
10     using System.Collections.Specialized;
11     using System.ComponentModel;
12     using System.Diagnostics;
13     using System.Diagnostics.CodeAnalysis;
14     using System.Drawing;
15     using System.Drawing.Design;
16     using System.Globalization;
17     using System.Security.Permissions;
18     using System.Text;
19     using System.Web.Configuration;
20     using System.Web.Management;
21     using System.Web.Security;
22
23
24     /// <devdoc>
25     /// Displays UI that allows a user to recover his/her password.  Prompts for username and possibly answer
26     /// to security question.  If successful, the user's password is sent to him/her via email.  Uses
27     /// a Membership provider.  UI can be customized using control properties or a template.
28     /// </devdoc>
29     [
30     Bindable(false),
31     DefaultEvent("SendingMail"),
32     Designer("System.Web.UI.Design.WebControls.PasswordRecoveryDesigner, " + AssemblyRef.SystemDesign)
33     ]
34     public class PasswordRecovery : CompositeControl, IBorderPaddingControl, IRenderOuterTableControl {
35         public static readonly string SubmitButtonCommandName = "Submit";
36
37         // Needed for user template feature
38         private const string _userNameID = "UserName";
39         private const string _questionID = "Question";
40         private const string _answerID = "Answer";
41         private const string _failureTextID = "FailureText";
42
43         // Needed only for "convert to template" feature, otherwise unnecessary
44         private const string _userNameRequiredID = "UserNameRequired";
45         private const string _answerRequiredID = "AnswerRequired";
46         private const string _pushButtonID = "SubmitButton";
47         private const string _imageButtonID = "SubmitImageButton";
48         private const string _linkButtonID = "SubmitLinkButton";
49         private const string _helpLinkID = "HelpLink";
50
51         private const string _userNameContainerID = "UserNameContainerID";
52         private const string _questionContainerID = "QuestionContainerID";
53         private const string _successContainerID = "SuccessContainerID";
54         private const ValidatorDisplay _requiredFieldValidatorDisplay = ValidatorDisplay.Static;
55         private const string _userNameReplacementKey = "<%\\s*UserName\\s*%>";
56         private const string _passwordReplacementKey = "<%\\s*Password\\s*%>";
57
58         private string _answer;
59         private View _currentView = View.UserName;
60         private string _question;
61         private string _userName;
62         private bool _convertingToTemplate = false;
63         private bool _renderDesignerRegion = false;
64
65         private ITemplate _userNameTemplate;
66         private UserNameContainer _userNameContainer;
67         private ITemplate _questionTemplate;
68         private QuestionContainer _questionContainer;
69         private ITemplate _successTemplate;
70         private SuccessContainer _successContainer;
71
72         private const int _viewStateArrayLength = 11;
73         private Style _submitButtonStyle;
74         private TableItemStyle _labelStyle;
75         private Style _textBoxStyle;
76         private TableItemStyle _hyperLinkStyle;
77         private TableItemStyle _instructionTextStyle;
78         private TableItemStyle _titleTextStyle;
79         private TableItemStyle _failureTextStyle;
80         private TableItemStyle _successTextStyle;
81         private MailDefinition _mailDefinition;
82         private Style _validatorTextStyle;
83
84         private static readonly object EventVerifyingUser = new object();
85         private static readonly object EventUserLookupError = new object();
86         private static readonly object EventVerifyingAnswer = new object();
87         private static readonly object EventAnswerLookupError = new object();
88         private static readonly object EventSendMailError = new object();
89         private static readonly object EventSendingMail = new object();
90
91
92         /// <devdoc>
93         /// Answer to the security question.
94         /// </devdoc>
95         [
96         Browsable(false),
97         Filterable(false),
98         Themeable(false),
99         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
100         ]
101         public virtual string Answer {
102             get {
103                 return (_answer == null) ? String.Empty : _answer;
104             }
105         }
106
107         private string AnswerInternal {
108             get {
109                 string answer = Answer;
110                 if (String.IsNullOrEmpty(answer) && _questionContainer != null) {
111                     ITextControl answerTextBox = (ITextControl)_questionContainer.AnswerTextBox;
112                     if (answerTextBox != null && answerTextBox.Text != null) {
113                         return answerTextBox.Text;
114                     }
115                 }
116                 return answer;
117             }
118         }
119
120         /// <devdoc>
121         /// The text that identifies the answer textbox.
122         /// </devdoc>
123         [
124         Localizable(true),
125         WebCategory("Appearance"),
126         WebSysDefaultValue(SR.PasswordRecovery_DefaultAnswerLabelText),
127         WebSysDescription(SR.PasswordRecovery_AnswerLabelText)
128         ]
129         public virtual string AnswerLabelText {
130             get {
131                 object obj = ViewState["AnswerLabelText"];
132                 return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultAnswerLabelText) : (string)obj;
133             }
134             set {
135                 ViewState["AnswerLabelText"] = value;
136             }
137         }
138
139
140         /// <devdoc>
141         /// The text to be shown in the validation summary when the answer is empty.
142         /// </devdoc>
143         [
144         Localizable(true),
145         WebCategory("Validation"),
146         WebSysDefaultValue(SR.PasswordRecovery_DefaultAnswerRequiredErrorMessage),
147         WebSysDescription(SR.LoginControls_AnswerRequiredErrorMessage)
148         ]
149         public virtual string AnswerRequiredErrorMessage {
150             get {
151                 object obj = ViewState["AnswerRequiredErrorMessage"];
152                 return (obj == null) ?
153                     SR.GetString(SR.PasswordRecovery_DefaultAnswerRequiredErrorMessage) : (string)obj;
154             }
155             set {
156                 ViewState["AnswerRequiredErrorMessage"] = value;
157             }
158         }
159
160
161         [
162         WebCategory("Appearance"),
163         DefaultValue(1),
164         WebSysDescription(SR.Login_BorderPadding),
165         SuppressMessage("Microsoft.Security", "CA2119:SealMethodsThatSatisfyPrivateInterfaces",
166             Justification = "Interface denotes existence of property, not used for security.")
167         ]
168         public virtual int BorderPadding {
169             get {
170                 object obj = ViewState["BorderPadding"];
171                 return (obj == null) ? 1 : (int)obj;
172             }
173             set {
174                 if (value < -1) {
175                     throw new ArgumentOutOfRangeException("value", SR.GetString(SR.PasswordRecovery_InvalidBorderPadding));
176                 }
177                 ViewState["BorderPadding"] = value;
178             }
179         }
180
181
182         /// <devdoc>
183         /// The style of the submit button.
184         /// </devdoc>
185         [
186         WebCategory("Styles"),
187         DefaultValue(null),
188         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
189         NotifyParentProperty(true),
190         PersistenceMode(PersistenceMode.InnerProperty),
191         WebSysDescription(SR.PasswordRecovery_SubmitButtonStyle)
192         ]
193         public Style SubmitButtonStyle {
194             get {
195                 if (_submitButtonStyle == null) {
196                     _submitButtonStyle = new Style();
197                     if (IsTrackingViewState) {
198                         ((IStateManager)_submitButtonStyle).TrackViewState();
199                     }
200                 }
201                 return _submitButtonStyle;
202             }
203         }
204
205
206         /// <devdoc>
207         /// The type of the submit button.
208         /// </devdoc>
209         [
210         WebCategory("Appearance"),
211         DefaultValue(ButtonType.Button),
212         WebSysDescription(SR.PasswordRecovery_SubmitButtonType)
213         ]
214         public virtual ButtonType SubmitButtonType {
215             get {
216                 object obj = ViewState["SubmitButtonType"];
217                 return (obj == null) ? ButtonType.Button : (ButtonType)obj;
218             }
219             set {
220                 if (value < ButtonType.Button || value > ButtonType.Link) {
221                     throw new ArgumentOutOfRangeException("value");
222                 }
223                 ViewState["SubmitButtonType"] = value;
224             }
225         }
226
227         private bool ConvertingToTemplate {
228             get {
229                 return (DesignMode && _convertingToTemplate);
230             }
231         }
232
233         /// <devdoc>
234         /// Internal because used from PasswordRecoveryAdapter.
235         /// </devdoc>
236         internal View CurrentView {
237             get {
238                 return _currentView;
239             }
240             set {
241                 if (value < View.UserName || value > View.Success) {
242                     throw new ArgumentOutOfRangeException("value");
243                 }
244                 if (value != CurrentView) {
245                     _currentView = value;
246                     UpdateValidators();
247                 }
248             }
249         }
250
251
252         /// <devdoc>
253         /// The style of the failure text.
254         /// </devdoc>
255         [
256         WebCategory("Styles"),
257         DefaultValue(null),
258         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
259         NotifyParentProperty(true),
260         PersistenceMode(PersistenceMode.InnerProperty),
261         WebSysDescription(SR.WebControl_FailureTextStyle)
262         ]
263         public TableItemStyle FailureTextStyle {
264             get {
265                 if (_failureTextStyle == null) {
266                     _failureTextStyle = new ErrorTableItemStyle();
267                     if (IsTrackingViewState) {
268                         ((IStateManager)_failureTextStyle).TrackViewState();
269                     }
270                 }
271                 return _failureTextStyle;
272             }
273         }
274
275
276         /// <devdoc>
277         /// The text to be shown when there is an unexpected failure.
278         /// </devdoc>
279         [
280         Localizable(true),
281         WebCategory("Appearance"),
282         WebSysDefaultValue(SR.PasswordRecovery_DefaultGeneralFailureText),
283         WebSysDescription(SR.PasswordRecovery_GeneralFailureText)
284         ]
285         public virtual string GeneralFailureText {
286             get {
287                 object obj = ViewState["GeneralFailureText"];
288                 return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultGeneralFailureText) : (string)obj;
289             }
290             set {
291                 ViewState["GeneralFailureText"] = value;
292             }
293         }
294
295
296         /// <devdoc>
297         /// The text to be shown for the help link.
298         /// </devdoc>
299         [
300         Localizable(true),
301         WebCategory("Links"),
302         DefaultValue(""),
303         WebSysDescription(SR.ChangePassword_HelpPageText)
304         ]
305         public virtual string HelpPageText {
306             get {
307                 object obj = ViewState["HelpPageText"];
308                 return (obj == null) ? String.Empty : (string)obj;
309             }
310             set {
311                 ViewState["HelpPageText"] = value;
312             }
313         }
314
315         [
316         WebCategory("Links"),
317         DefaultValue(""),
318         WebSysDescription(SR.LoginControls_HelpPageIconUrl),
319         Editor("System.Web.UI.Design.ImageUrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
320         UrlProperty()
321         ]
322         public virtual string HelpPageIconUrl {
323             get {
324                 object obj = ViewState["HelpPageIconUrl"];
325                 return (obj == null) ? String.Empty : (string)obj;
326             }
327             set {
328                 ViewState["HelpPageIconUrl"] = value;
329             }
330         }
331
332
333         /// <devdoc>
334         /// The URL of the help page.
335         /// </devdoc>
336         [
337         WebCategory("Links"),
338         DefaultValue(""),
339         WebSysDescription(SR.LoginControls_HelpPageUrl),
340         Editor("System.Web.UI.Design.UrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
341         UrlProperty()
342         ]
343         public virtual string HelpPageUrl {
344             get {
345                 object obj = ViewState["HelpPageUrl"];
346                 return (obj == null) ? String.Empty : (string)obj;
347             }
348             set {
349                 ViewState["HelpPageUrl"] = value;
350             }
351         }
352
353
354         /// <devdoc>
355         /// The style of the hyperlinks.
356         /// </devdoc>
357         [
358         WebCategory("Styles"),
359         DefaultValue(null),
360         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
361         NotifyParentProperty(true),
362         PersistenceMode(PersistenceMode.InnerProperty),
363         WebSysDescription(SR.WebControl_HyperLinkStyle)
364         ]
365         public TableItemStyle HyperLinkStyle {
366             get {
367                 if (_hyperLinkStyle == null) {
368                     _hyperLinkStyle = new TableItemStyle();
369                     if (IsTrackingViewState) {
370                         ((IStateManager)_hyperLinkStyle).TrackViewState();
371                     }
372                 }
373                 return _hyperLinkStyle;
374             }
375         }
376
377
378         /// <devdoc>
379         /// The style of the instructions.
380         /// </devdoc>
381         [
382         WebCategory("Styles"),
383         DefaultValue(null),
384         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
385         NotifyParentProperty(true),
386         PersistenceMode(PersistenceMode.InnerProperty),
387         WebSysDescription(SR.WebControl_InstructionTextStyle)
388         ]
389         public TableItemStyle InstructionTextStyle {
390             get {
391                 if (_instructionTextStyle == null) {
392                     _instructionTextStyle = new TableItemStyle();
393                     if (IsTrackingViewState) {
394                         ((IStateManager)_instructionTextStyle).TrackViewState();
395                     }
396                 }
397                 return _instructionTextStyle;
398             }
399         }
400
401
402         /// <devdoc>
403         /// The style of the textbox labels.
404         /// </devdoc>
405         [
406         WebCategory("Styles"),
407         DefaultValue(null),
408         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
409         NotifyParentProperty(true),
410         PersistenceMode(PersistenceMode.InnerProperty),
411         WebSysDescription(SR.LoginControls_LabelStyle)
412         ]
413         public TableItemStyle LabelStyle {
414             get {
415                 if (_labelStyle == null) {
416                     _labelStyle = new TableItemStyle();
417                     if (IsTrackingViewState) {
418                         ((IStateManager)_labelStyle).TrackViewState();
419                     }
420                 }
421                 return _labelStyle;
422             }
423         }
424
425
426         /// <devdoc>
427         /// The content and format of the e-mail message that contains the new password.
428         /// </devdoc>
429         [
430         WebCategory("Behavior"),
431         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
432         NotifyParentProperty(true),
433         PersistenceMode(PersistenceMode.InnerProperty),
434         Themeable(false),
435         WebSysDescription(SR.PasswordRecovery_MailDefinition)
436         ]
437         public MailDefinition MailDefinition {
438             get {
439                 if (_mailDefinition == null) {
440                     _mailDefinition = new MailDefinition();
441                     if (IsTrackingViewState) {
442                         ((IStateManager)_mailDefinition).TrackViewState();
443                     }
444                 }
445                 return _mailDefinition;
446             }
447         }
448
449
450         /// <devdoc>
451         ///     Gets or sets the name of the membership provider.  If null or empty, the default provider is used.
452         /// </devdoc>
453         [
454         WebCategory("Data"),
455         DefaultValue(""),
456         Themeable(false),
457         WebSysDescription(SR.MembershipProvider_Name)
458         ]
459         public virtual string MembershipProvider {
460             get {
461                 object obj = ViewState["MembershipProvider"];
462                 return (obj == null) ? String.Empty : (string)obj;
463             }
464             set {
465                 ViewState["MembershipProvider"] = value;
466             }
467         }
468
469
470         /// <devdoc>
471         /// The security question.
472         /// </devdoc>
473         [
474         Browsable(false),
475         Filterable(false),
476         Themeable(false),
477         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
478         ]
479         public virtual string Question {
480             get {
481                 return (_question != null) ? _question : String.Empty;
482             }
483             private set {
484                 _question = value;
485             }
486         }
487
488
489         /// <devdoc>
490         /// The text to be shown when the answer is incorrect.
491         /// </devdoc>
492         [
493         Localizable(true),
494         WebCategory("Appearance"),
495         WebSysDefaultValue(SR.PasswordRecovery_DefaultQuestionFailureText),
496         WebSysDescription(SR.PasswordRecovery_QuestionFailureText)
497         ]
498         public virtual string QuestionFailureText {
499             get {
500                 object obj = ViewState["QuestionFailureText"];
501                 return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultQuestionFailureText) : (string)obj;
502             }
503             set {
504                 ViewState["QuestionFailureText"] = value;
505             }
506         }
507
508
509         /// <devdoc>
510         /// Text that is displayed to give instructions for answering the question.
511         /// </devdoc>
512         [
513         Localizable(true),
514         WebCategory("Appearance"),
515         WebSysDefaultValue(SR.PasswordRecovery_DefaultQuestionInstructionText),
516         WebSysDescription(SR.PasswordRecovery_QuestionInstructionText)
517         ]
518         public virtual string QuestionInstructionText {
519             get {
520                 object obj = ViewState["QuestionInstructionText"];
521                 return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultQuestionInstructionText) : (string)obj;
522             }
523             set {
524                 ViewState["QuestionInstructionText"] = value;
525             }
526         }
527
528
529         /// <devdoc>
530         /// The text that identifies the question.
531         /// </devdoc>
532         [
533         Localizable(true),
534         WebCategory("Appearance"),
535         WebSysDefaultValue(SR.PasswordRecovery_DefaultQuestionLabelText),
536         WebSysDescription(SR.PasswordRecovery_QuestionLabelText)
537         ]
538         public virtual string QuestionLabelText {
539             get {
540                 object obj = ViewState["QuestionLabelText"];
541                 return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultQuestionLabelText) : (string)obj;
542             }
543             set {
544                 ViewState["QuestionLabelText"] = value;
545             }
546         }
547
548
549         /// <devdoc>
550         /// The text to be shown for the title when answering the question.
551         /// </devdoc>
552         [
553         Localizable(true),
554         WebCategory("Appearance"),
555         WebSysDefaultValue(SR.PasswordRecovery_DefaultQuestionTitleText),
556         WebSysDescription(SR.PasswordRecovery_QuestionTitleText)
557         ]
558         public virtual string QuestionTitleText {
559             get {
560                 object obj = ViewState["QuestionTitleText"];
561                 return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultQuestionTitleText) : (string)obj;
562             }
563             set {
564                 ViewState["QuestionTitleText"] = value;
565             }
566         }
567
568
569         /// <devdoc>
570         /// Template rendered to prompt the user for an answer to the security question.
571         /// </devdoc>
572         [
573         Browsable(false),
574         PersistenceMode(PersistenceMode.InnerProperty),
575         TemplateContainer(typeof(PasswordRecovery)),
576         WebSysDescription(SR.PasswordRecovery_QuestionTemplate)
577         ]
578         public virtual ITemplate QuestionTemplate {
579             get {
580                 return _questionTemplate;
581             }
582             set {
583                 _questionTemplate = value;
584                 ChildControlsCreated = false;
585             }
586         }
587
588         /// <devdoc>
589         /// Internal because used from PasswordRecoveryAdapter.
590         /// </devdoc>
591         [
592         Browsable(false),
593         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
594         WebSysDescription(SR.PasswordRecovery_QuestionTemplateContainer)
595         ]
596         public Control QuestionTemplateContainer {
597             get {
598                 EnsureChildControls();
599                 return _questionContainer;
600             }
601         }
602
603
604         /// <devdoc>
605         /// The URL of an image to be displayed for the submit button.
606         /// </devdoc>
607         [
608         WebCategory("Appearance"),
609         DefaultValue(""),
610         WebSysDescription(SR.ChangePassword_ChangePasswordButtonImageUrl),
611         Editor("System.Web.UI.Design.ImageUrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
612         UrlProperty()
613         ]
614         public virtual string SubmitButtonImageUrl {
615             get {
616                 object obj = ViewState["SubmitButtonImageUrl"];
617                 return (obj == null) ? String.Empty : (string)obj;
618             }
619             set {
620                 ViewState["SubmitButtonImageUrl"] = value;
621             }
622         }
623
624
625         /// <devdoc>
626         /// The text to be shown for the submit button.
627         /// </devdoc>
628         [
629         Localizable(true),
630         WebCategory("Appearance"),
631         WebSysDefaultValue(SR.PasswordRecovery_DefaultSubmitButtonText),
632         WebSysDescription(SR.ChangePassword_ChangePasswordButtonText)
633         ]
634         public virtual string SubmitButtonText {
635             get {
636                 object obj = ViewState["SubmitButtonText"];
637                 return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultSubmitButtonText) : (string)obj;
638             }
639             set {
640                 ViewState["SubmitButtonText"] = value;
641             }
642         }
643
644
645         /// <devdoc>
646         /// The URL that the user is directed to after the password e-mail has been sent.
647         /// If non-null, always redirect the user to this page after successful password recovery.  Else, perform the refresh action.
648         /// </devdoc>
649         [
650         WebCategory("Behavior"),
651         DefaultValue(""),
652         WebSysDescription(SR.LoginControls_SuccessPageUrl),
653         Editor("System.Web.UI.Design.UrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
654         Themeable(false),
655         UrlProperty()
656         ]
657         public virtual string SuccessPageUrl {
658             get {
659                 object obj = ViewState["SuccessPageUrl"];
660                 return (obj == null) ? String.Empty : (string)obj;
661             }
662             set {
663                 ViewState["SuccessPageUrl"] = value;
664             }
665         }
666
667
668         /// <devdoc>
669         /// Template rendered after the e-mail is sent.
670         /// </devdoc>
671         [
672         Browsable(false),
673         PersistenceMode(PersistenceMode.InnerProperty),
674         WebSysDescription(SR.PasswordRecovery_SuccessTemplate),
675         TemplateContainer(typeof(PasswordRecovery))
676         ]
677         public virtual ITemplate SuccessTemplate {
678             get {
679                 return _successTemplate;
680             }
681             set {
682                 _successTemplate = value;
683                 ChildControlsCreated = false;
684             }
685         }
686
687         /// <devdoc>
688         /// Internal because used from PasswordRecoveryAdapter.
689         /// </devdoc>
690         [
691         Browsable(false),
692         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
693         WebSysDescription(SR.PasswordRecovery_SuccessTemplateContainer)
694         ]
695         public Control SuccessTemplateContainer {
696             get {
697                 EnsureChildControls();
698                 return _successContainer;
699             }
700         }
701
702
703         /// <devdoc>
704         /// The text to be shown after the password e-mail has been sent.
705         /// </devdoc>
706         [
707         Localizable(true),
708         WebCategory("Appearance"),
709         WebSysDefaultValue(SR.PasswordRecovery_DefaultSuccessText),
710         WebSysDescription(SR.PasswordRecovery_SuccessText)
711         ]
712         public virtual string SuccessText {
713             get {
714                 object obj = ViewState["SuccessText"];
715                 return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultSuccessText) : (string)obj;
716             }
717             set {
718                 ViewState["SuccessText"] = value;
719             }
720         }
721
722
723         /// <devdoc>
724         /// The style of the success text.
725         /// </devdoc>
726         [
727         WebCategory("Styles"),
728         DefaultValue(null),
729         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
730         NotifyParentProperty(true),
731         PersistenceMode(PersistenceMode.InnerProperty),
732         WebSysDescription(SR.PasswordRecovery_SuccessTextStyle)
733         ]
734         public TableItemStyle SuccessTextStyle {
735             get {
736                 if (_successTextStyle == null) {
737                     _successTextStyle = new TableItemStyle();
738                     if (IsTrackingViewState) {
739                         ((IStateManager)_successTextStyle).TrackViewState();
740                     }
741                 }
742                 return _successTextStyle;
743             }
744         }
745
746         [
747         WebCategory("Layout"),
748         DefaultValue(true),
749         WebSysDescription(SR.LoginControls_RenderOuterTable),
750         SuppressMessage("Microsoft.Security", "CA2119:SealMethodsThatSatisfyPrivateInterfaces",
751             Justification = "Interface denotes existence of property, not used for security.")
752         ]
753         public virtual bool RenderOuterTable {
754             get {
755                 object obj = ViewState["RenderOuterTable"];
756                 return (obj == null) ? true : (bool)obj;
757             }
758             set {
759                 ViewState["RenderOuterTable"] = value;
760             }
761         }
762
763         protected override HtmlTextWriterTag TagKey {
764             get {
765                 return HtmlTextWriterTag.Table;
766             }
767         }
768
769
770         /// <devdoc>
771         /// The style of the textboxes.
772         /// </devdoc>
773         [
774         WebCategory("Styles"),
775         DefaultValue(null),
776         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
777         NotifyParentProperty(true),
778         PersistenceMode(PersistenceMode.InnerProperty),
779         WebSysDescription(SR.LoginControls_TextBoxStyle)
780         ]
781         public Style TextBoxStyle {
782             get {
783                 if (_textBoxStyle == null) {
784                     _textBoxStyle = new Style();
785                     if (IsTrackingViewState) {
786                         ((IStateManager)_textBoxStyle).TrackViewState();
787                     }
788                 }
789                 return _textBoxStyle;
790             }
791         }
792
793
794         /// <devdoc>
795         /// The layout of the labels in relation to the textboxes.
796         /// </devdoc>
797         [
798         WebCategory("Layout"),
799         DefaultValue(LoginTextLayout.TextOnLeft),
800         WebSysDescription(SR.LoginControls_TextLayout)
801         ]
802         public virtual LoginTextLayout TextLayout {
803             get {
804                 object obj = ViewState["TextLayout"];
805                 return (obj == null) ? LoginTextLayout.TextOnLeft : (LoginTextLayout)obj;
806             }
807             set {
808                 if (value < LoginTextLayout.TextOnLeft || value > LoginTextLayout.TextOnTop) {
809                     throw new ArgumentOutOfRangeException("value");
810                 }
811                 ViewState["TextLayout"] = value;
812                 ChildControlsCreated = false;
813             }
814         }
815
816
817         /// <devdoc>
818         /// The style of the title.
819         /// </devdoc>
820         [
821         WebCategory("Styles"),
822         DefaultValue(null),
823         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
824         NotifyParentProperty(true),
825         PersistenceMode(PersistenceMode.InnerProperty),
826         WebSysDescription(SR.LoginControls_TitleTextStyle)
827         ]
828         public TableItemStyle TitleTextStyle {
829             get {
830                 if (_titleTextStyle == null) {
831                     _titleTextStyle = new TableItemStyle();
832                     if (IsTrackingViewState) {
833                         ((IStateManager)_titleTextStyle).TrackViewState();
834                     }
835                 }
836                 return _titleTextStyle;
837             }
838         }
839
840
841         /// <devdoc>
842         /// The initial value in the user name textbox.
843         /// </devdoc>
844         [
845         Localizable(true),
846         WebCategory("Appearance"),
847         DefaultValue(""),
848         WebSysDescription(SR.UserName_InitialValue)
849         ]
850         public virtual string UserName {
851             get {
852                 return (_userName == null) ? String.Empty : _userName;
853             }
854             set {
855                 _userName = value;
856             }
857         }
858
859         internal string UserNameInternal {
860             get {
861                 string userName = UserName;
862                 if (String.IsNullOrEmpty(userName) && _userNameContainer != null) {
863                     ITextControl textbox = _userNameContainer.UserNameTextBox as ITextControl;
864                     if (textbox != null) {
865                         return textbox.Text;
866                     }
867                 }
868                 return userName;
869             }
870         }
871
872
873         /// <devdoc>
874         /// The text to be shown when the user name is invalid.
875         /// </devdoc>
876         [
877         Localizable(true),
878         WebCategory("Appearance"),
879         WebSysDefaultValue(SR.PasswordRecovery_DefaultUserNameFailureText),
880         WebSysDescription(SR.PasswordRecovery_UserNameFailureText)
881         ]
882         public virtual string UserNameFailureText {
883             get {
884                 object obj = ViewState["UserNameFailureText"];
885                 return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultUserNameFailureText) : (string)obj;
886             }
887             set {
888                 ViewState["UserNameFailureText"] = value;
889             }
890         }
891
892
893         /// <devdoc>
894         /// Text that is displayed to give instructions for entering the user name.
895         /// </devdoc>
896         [
897         Localizable(true),
898         WebCategory("Appearance"),
899         WebSysDefaultValue(SR.PasswordRecovery_DefaultUserNameInstructionText),
900         WebSysDescription(SR.PasswordRecovery_UserNameInstructionText)
901         ]
902         public virtual string UserNameInstructionText {
903             get {
904                 object obj = ViewState["UserNameInstructionText"];
905                 return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultUserNameInstructionText) : (string)obj;
906             }
907             set {
908                 ViewState["UserNameInstructionText"] = value;
909             }
910         }
911
912
913         /// <devdoc>
914         /// The text that identifies the user name.
915         /// </devdoc>
916         [
917         Localizable(true),
918         WebCategory("Appearance"),
919         WebSysDefaultValue(SR.PasswordRecovery_DefaultUserNameLabelText),
920         WebSysDescription(SR.PasswordRecovery_UserNameLabelText)
921         ]
922         public virtual string UserNameLabelText {
923             get {
924                 object obj = ViewState["UserNameLabelText"];
925                 return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultUserNameLabelText) : (string)obj;
926             }
927             set {
928                 ViewState["UserNameLabelText"] = value;
929             }
930         }
931
932
933         /// <devdoc>
934         /// The text to be shown in the validation summary when the user name is empty.
935         /// </devdoc>
936         [
937         Localizable(true),
938         WebCategory("Validation"),
939         WebSysDefaultValue(SR.PasswordRecovery_DefaultUserNameRequiredErrorMessage),
940         WebSysDescription(SR.ChangePassword_UserNameRequiredErrorMessage)
941         ]
942         public virtual string UserNameRequiredErrorMessage {
943             get {
944                 object obj = ViewState["UserNameRequiredErrorMessage"];
945                 return (obj == null) ?
946                     SR.GetString(SR.PasswordRecovery_DefaultUserNameRequiredErrorMessage) : (string)obj;
947             }
948             set {
949                 ViewState["UserNameRequiredErrorMessage"] = value;
950             }
951         }
952
953
954         /// <devdoc>
955         /// Template rendered to prompt the user to enter a user name.
956         /// </devdoc>
957         [
958         Browsable(false),
959         PersistenceMode(PersistenceMode.InnerProperty),
960         TemplateContainer(typeof(PasswordRecovery)),
961         WebSysDescription(SR.PasswordRecovery_UserNameTemplate)
962         ]
963         public virtual ITemplate UserNameTemplate {
964             get {
965                 return _userNameTemplate;
966             }
967             set {
968                 _userNameTemplate = value;
969                 ChildControlsCreated = false;
970             }
971         }
972
973         /// <devdoc>
974         /// Internal because used from PasswordRecoveryAdapter.
975         /// </devdoc>
976         [
977         Browsable(false),
978         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
979         WebSysDescription(SR.PasswordRecovery_UserNameTemplateContainer)
980         ]
981         public Control UserNameTemplateContainer {
982             get {
983                 EnsureChildControls();
984                 return _userNameContainer;
985             }
986         }
987
988
989         /// <devdoc>
990         /// The text to be shown for the title when entering the user name.
991         /// </devdoc>
992         [
993         Localizable(true),
994         WebCategory("Appearance"),
995         WebSysDefaultValue(SR.PasswordRecovery_DefaultUserNameTitleText),
996         WebSysDescription(SR.PasswordRecovery_UserNameTitleText)
997         ]
998         public virtual string UserNameTitleText {
999             get {
1000                 object obj = ViewState["UserNameTitleText"];
1001                 return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultUserNameTitleText) : (string)obj;
1002             }
1003             set {
1004                 ViewState["UserNameTitleText"] = value;
1005             }
1006         }
1007
1008         [
1009         WebCategory("Styles"),
1010         DefaultValue(null),
1011         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
1012         NotifyParentProperty(true),
1013         PersistenceMode(PersistenceMode.InnerProperty),
1014         WebSysDescription(SR.ChangePassword_ValidatorTextStyle)
1015         ]
1016         public Style ValidatorTextStyle {
1017             get {
1018                 if (_validatorTextStyle == null) {
1019                     _validatorTextStyle = new ErrorStyle();
1020                     if (IsTrackingViewState) {
1021                         ((IStateManager)_validatorTextStyle).TrackViewState();
1022                     }
1023                 }
1024                 return _validatorTextStyle;
1025             }
1026         }
1027
1028
1029
1030         /// <devdoc>
1031         /// Raised when the answer provided is incorrect.
1032         /// </devdoc>
1033         [
1034         WebCategory("Action"),
1035         WebSysDescription(SR.PasswordRecovery_AnswerLookupError)
1036         ]
1037         public event EventHandler AnswerLookupError {
1038             add {
1039                 Events.AddHandler(EventAnswerLookupError, value);
1040             }
1041             remove {
1042                 Events.RemoveHandler(EventAnswerLookupError, value);
1043             }
1044         }
1045
1046
1047         /// <devdoc>
1048         /// Raised before the answer is validated.
1049         /// </devdoc>
1050         [
1051         WebCategory("Action"),
1052         WebSysDescription(SR.PasswordRecovery_VerifyingAnswer)
1053         ]
1054         public event LoginCancelEventHandler VerifyingAnswer {
1055             add {
1056                 Events.AddHandler(EventVerifyingAnswer, value);
1057             }
1058             remove {
1059                 Events.RemoveHandler(EventVerifyingAnswer, value);
1060             }
1061         }
1062
1063
1064         /// <devdoc>
1065         /// Raised before the e-mail is sent.
1066         /// </devdoc>
1067         [
1068         WebCategory("Action"),
1069         WebSysDescription(SR.PasswordRecovery_SendingMail)
1070         ]
1071         public event MailMessageEventHandler SendingMail {
1072             add {
1073                 Events.AddHandler(EventSendingMail, value);
1074             }
1075             remove {
1076                 Events.RemoveHandler(EventSendingMail, value);
1077             }
1078         }
1079
1080         [
1081         WebCategory("Action"),
1082         WebSysDescription(SR.CreateUserWizard_SendMailError)
1083         ]
1084         public event SendMailErrorEventHandler SendMailError {
1085             add {
1086                 Events.AddHandler(EventSendMailError, value);
1087             }
1088             remove {
1089                 Events.RemoveHandler(EventSendMailError, value);
1090             }
1091         }
1092
1093
1094         /// <devdoc>
1095         /// Raised before the username is looked up.
1096         /// </devdoc>
1097         [
1098         WebCategory("Action"),
1099         WebSysDescription(SR.PasswordRecovery_VerifyingUser)
1100         ]
1101         public event LoginCancelEventHandler VerifyingUser {
1102             add {
1103                 Events.AddHandler(EventVerifyingUser, value);
1104             }
1105             remove {
1106                 Events.RemoveHandler(EventVerifyingUser, value);
1107             }
1108         }
1109
1110
1111         /// <devdoc>
1112         /// Raised when the user name is invalid.
1113         /// </devdoc>
1114         [
1115         WebCategory("Action"),
1116         WebSysDescription(SR.PasswordRecovery_UserLookupError)
1117         ]
1118         public event EventHandler UserLookupError {
1119             add {
1120                 Events.AddHandler(EventUserLookupError, value);
1121             }
1122             remove {
1123                 Events.RemoveHandler(EventUserLookupError, value);
1124             }
1125         }
1126
1127         /// <devdoc>
1128         /// Called when the answer text box changes.
1129         /// </devdoc>
1130         private void AnswerTextChanged(object source, EventArgs e) {
1131             _answer = ((ITextControl)source).Text;
1132         }
1133
1134         private void AttemptSendPassword() {
1135             if (Page != null && !Page.IsValid) {
1136                 return;
1137             }
1138
1139             if (CurrentView == View.UserName) {
1140                 AttemptSendPasswordUserNameView();
1141             }
1142             else if (CurrentView == View.Question) {
1143                 AttemptSendPasswordQuestionView();
1144             }
1145         }
1146
1147         /// <devdoc>
1148         /// Called when the user presses submit in the question view.
1149         /// Verifies the answer to the security question.  If correct, sends password in e-mail.
1150         /// If answer is incorrect or there is any other error, a failure message is shown.
1151         /// </devdoc>
1152         private void AttemptSendPasswordQuestionView() {
1153             MembershipProvider provider = LoginUtil.GetProvider(MembershipProvider);
1154             MembershipUser user = provider.GetUser(UserNameInternal, /*userIsOnline*/ false, /*throwOnError*/ false);
1155             if (user != null) {
1156                 if (user.IsLockedOut) {
1157                     SetFailureTextLabel(_questionContainer, GeneralFailureText);
1158                     return;
1159                 }
1160
1161                 Question = user.PasswordQuestion;
1162                 if (String.IsNullOrEmpty(Question)) {
1163                     SetFailureTextLabel(_questionContainer, GeneralFailureText);
1164                     return;
1165                 }
1166
1167                 LoginCancelEventArgs cancelEventArgs = new LoginCancelEventArgs();
1168                 OnVerifyingAnswer(cancelEventArgs);
1169                 if (cancelEventArgs.Cancel) {
1170                     return;
1171                 }
1172
1173                 string answer = AnswerInternal;
1174                 string password = null;
1175                 string email = user.Email;
1176                 // If there is no email address, show the GeneralFailureText and return immediately.
1177                 // We must be especially sure we do not reset the password if we do not have an
1178                 // email address. (VSWhidbey 387663)
1179                 if (String.IsNullOrEmpty(email)) {
1180                     SetFailureTextLabel(_questionContainer, GeneralFailureText);
1181                     return;
1182                 }
1183
1184                 if (provider.EnablePasswordRetrieval) {
1185                     password = user.GetPassword(answer, /*throwOnError*/ false);
1186                 }
1187                 else if (provider.EnablePasswordReset) {
1188                     password = user.ResetPassword(answer, /*throwOnError*/ false);
1189                 }
1190                 else {
1191                     throw new HttpException(SR.GetString(SR.PasswordRecovery_RecoveryNotSupported));
1192                 }
1193
1194                 if (password != null) {
1195                     LoginUtil.SendPasswordMail(email, user.UserName, password, MailDefinition,
1196                                                SR.GetString(SR.PasswordRecovery_DefaultSubject),
1197                                                SR.GetString(SR.PasswordRecovery_DefaultBody),
1198                                                OnSendingMail, OnSendMailError, this);
1199                     PerformSuccessAction();
1200                 }
1201                 else {
1202                     OnAnswerLookupError(EventArgs.Empty);
1203                     SetFailureTextLabel(_questionContainer, QuestionFailureText);
1204                 }
1205             }
1206             else {
1207                 // If the user lookup fails after it succeeded in the previous view,
1208                 // it is considered a general failure
1209                 SetFailureTextLabel(_questionContainer, GeneralFailureText);
1210             }
1211         }
1212
1213         /// <devdoc>
1214         /// Called when the user presses submit in the user name view.
1215         /// If user name is valid, sends password in e-mail.
1216         /// If user name is invalid or there is any other error, a failure message is shown.
1217         /// </devdoc>
1218         private void AttemptSendPasswordUserNameView() {
1219             LoginCancelEventArgs cancelEventArgs = new LoginCancelEventArgs();
1220             OnVerifyingUser(cancelEventArgs);
1221             if (cancelEventArgs.Cancel) {
1222                 return;
1223             }
1224
1225             MembershipProvider provider = LoginUtil.GetProvider(MembershipProvider);
1226             MembershipUser user = provider.GetUser(UserNameInternal, /*isUserOnline*/ false, /*throwOnError*/ false);
1227             if (user != null) {
1228                 if (user.IsLockedOut) {
1229                     SetFailureTextLabel(_userNameContainer, UserNameFailureText);
1230                     return;
1231                 }
1232
1233                 if (provider.RequiresQuestionAndAnswer) {
1234                     Question = user.PasswordQuestion;
1235                     if (String.IsNullOrEmpty(Question)) {
1236                         SetFailureTextLabel(_userNameContainer, GeneralFailureText);
1237                         return;
1238                     }
1239                     CurrentView = View.Question;
1240                 }
1241                 else {
1242                     string password = null;
1243                     string email = user.Email;
1244                     // If there is no email address, show the GeneralFailureText and return immediately.
1245                     // We must be especially sure we do not reset the password if we do not have an
1246                     // email address. (VSWhidbey 387663)                     
1247                     if (String.IsNullOrEmpty(email)) {
1248                         SetFailureTextLabel(_userNameContainer, GeneralFailureText);
1249                         return;
1250                     }
1251
1252                     if (provider.EnablePasswordRetrieval) {
1253                         password = user.GetPassword(/*throwOnError*/ false);
1254                     }
1255                     else if (provider.EnablePasswordReset) {
1256                         password = user.ResetPassword(/*throwOnError*/ false);
1257                     }
1258                     else {
1259                         throw new HttpException(SR.GetString(SR.PasswordRecovery_RecoveryNotSupported));
1260                     }
1261
1262                     if (password != null) {
1263                         LoginUtil.SendPasswordMail(email, user.UserName, password, MailDefinition,
1264                                                    SR.GetString(SR.PasswordRecovery_DefaultSubject),
1265                                                    SR.GetString(SR.PasswordRecovery_DefaultBody),
1266                                                    OnSendingMail, OnSendMailError, this);
1267                         PerformSuccessAction();
1268                     }
1269                     else {
1270                         SetFailureTextLabel(_userNameContainer, GeneralFailureText);
1271                     }
1272                 }
1273             }
1274             else {
1275                 OnUserLookupError(EventArgs.Empty);
1276                 SetFailureTextLabel(_userNameContainer, UserNameFailureText);
1277             }
1278         }
1279
1280
1281         /// <devdoc>
1282         /// Instantiates the proper template in the template container, and wires up necessary events.
1283         /// </devdoc>
1284         protected internal override void CreateChildControls() {
1285             Controls.Clear();
1286             CreateUserView();
1287             CreateQuestionView();
1288             CreateSuccessView();
1289         }
1290
1291         private void CreateQuestionView() {
1292             ITemplate template = null;
1293             _questionContainer = new QuestionContainer(this);
1294             _questionContainer.ID = _questionContainerID;
1295             _questionContainer.RenderDesignerRegion = _renderDesignerRegion;
1296             if (QuestionTemplate != null) {
1297                 template = QuestionTemplate;
1298             }
1299             else {
1300                 // 
1301                 template = new DefaultQuestionTemplate(this);
1302                 _questionContainer.EnableViewState = false;
1303
1304                 // Disable theming if using default template (VSWhidbey 86010)
1305                 _questionContainer.EnableTheming = false;
1306
1307             }
1308             template.InstantiateIn(_questionContainer);
1309             Controls.Add(_questionContainer);
1310
1311             IEditableTextControl answerTextBox = _questionContainer.AnswerTextBox as IEditableTextControl;
1312             if (answerTextBox != null) {
1313                 answerTextBox.TextChanged += new EventHandler(AnswerTextChanged);
1314             }
1315         }
1316
1317         private void CreateSuccessView() {
1318             ITemplate template = null;
1319             _successContainer = new SuccessContainer(this);
1320             _successContainer.ID = _successContainerID;
1321             _successContainer.RenderDesignerRegion = _renderDesignerRegion;
1322             if (SuccessTemplate != null) {
1323                 template = SuccessTemplate;
1324             }
1325             else {
1326                 // 
1327                 template = new DefaultSuccessTemplate(this);
1328                 _successContainer.EnableViewState = false;
1329
1330                 // Disable theming if using default template (VSWhidbey 86010)
1331                 _successContainer.EnableTheming = false;
1332             }
1333             template.InstantiateIn(_successContainer);
1334             Controls.Add(_successContainer);
1335         }
1336
1337         private void CreateUserView() {
1338             ITemplate template = null;
1339             _userNameContainer = new UserNameContainer(this);
1340             _userNameContainer.ID = _userNameContainerID;
1341             _userNameContainer.RenderDesignerRegion = _renderDesignerRegion;
1342             if (UserNameTemplate != null) {
1343                 template = UserNameTemplate;
1344             }
1345             else {
1346                 // 
1347                 template = new DefaultUserNameTemplate(this);
1348                 _userNameContainer.EnableViewState = false;
1349
1350                 // Disable theming if using default template (VSWhidbey 86010)
1351                 _userNameContainer.EnableTheming = false;
1352
1353             }
1354             template.InstantiateIn(_userNameContainer);
1355             Controls.Add(_userNameContainer);
1356
1357             // Set the editable child control properties here for two reasons:
1358             // - So change events will be raised if viewstate is disabled on the child controls
1359             //   - Viewstate is always disabled for default template, and might be for user template
1360             // - So the controls render correctly in the designer
1361             SetUserNameEditableChildProperties();
1362
1363             IEditableTextControl userNameTextBox = _userNameContainer.UserNameTextBox as IEditableTextControl;
1364             if (userNameTextBox != null) {
1365                 userNameTextBox.TextChanged += new EventHandler(UserNameTextChanged);
1366             }
1367         }
1368
1369         /// <devdoc>
1370         /// Loads the control state for those properties that should persist across postbacks
1371         /// even when EnableViewState=false.
1372         /// </devdoc>
1373         protected internal override void LoadControlState(object savedState) {
1374             if (savedState != null) {
1375                 Triplet state = (Triplet)savedState;
1376                 if (state.First != null) {
1377                     base.LoadControlState(state.First);
1378                 }
1379                 if (state.Second != null) {
1380                     CurrentView = (View)(int)state.Second;
1381                 }
1382                 if (state.Third != null) {
1383                     _userName = (string)state.Third;
1384                 }
1385             }
1386         }
1387
1388
1389         /// <devdoc>
1390         ///     Loads a saved state of the <see cref='System.Web.UI.WebControls.Login'/>.
1391         /// </devdoc>
1392         protected override void LoadViewState(object savedState) {
1393             if (savedState == null) {
1394                 base.LoadViewState(null);
1395             }
1396             else {
1397                 object[] myState = (object[])savedState;
1398                 if (myState.Length != _viewStateArrayLength) {
1399                     throw new ArgumentException(SR.GetString(SR.ViewState_InvalidViewState));
1400                 }
1401
1402                 base.LoadViewState(myState[0]);
1403                 if (myState[1] != null) {
1404                     ((IStateManager)SubmitButtonStyle).LoadViewState(myState[1]);
1405                 }
1406                 if (myState[2] != null) {
1407                     ((IStateManager)LabelStyle).LoadViewState(myState[2]);
1408                 }
1409                 if (myState[3] != null) {
1410                     ((IStateManager)TextBoxStyle).LoadViewState(myState[3]);
1411                 }
1412                 if (myState[4] != null) {
1413                     ((IStateManager)HyperLinkStyle).LoadViewState(myState[4]);
1414                 }
1415                 if (myState[5] != null) {
1416                     ((IStateManager)InstructionTextStyle).LoadViewState(myState[5]);
1417                 }
1418                 if (myState[6] != null) {
1419                     ((IStateManager)TitleTextStyle).LoadViewState(myState[6]);
1420                 }
1421                 if (myState[7] != null) {
1422                     ((IStateManager)FailureTextStyle).LoadViewState(myState[7]);
1423                 }
1424                 if (myState[8] != null) {
1425                     ((IStateManager)SuccessTextStyle).LoadViewState(myState[8]);
1426                 }
1427                 if (myState[9] != null) {
1428                     ((IStateManager)MailDefinition).LoadViewState(myState[9]);
1429                 }
1430                 if (myState[10] != null) {
1431                     ((IStateManager)ValidatorTextStyle).LoadViewState(myState[10]);
1432                 }
1433             }
1434         }
1435
1436
1437         /// <devdoc>
1438         /// Raises the AnswerLookup event.
1439         /// </devdoc>
1440         protected virtual void OnAnswerLookupError(EventArgs e) {
1441             EventHandler handler = (EventHandler)Events[EventAnswerLookupError];
1442             if (handler != null) {
1443                 handler(this, e);
1444             }
1445         }
1446
1447
1448         /// <devdoc>
1449         /// Raises the VerifyingAnswer event.
1450         /// </devdoc>
1451         protected virtual void OnVerifyingAnswer(LoginCancelEventArgs e) {
1452             LoginCancelEventHandler handler = (LoginCancelEventHandler)Events[EventVerifyingAnswer];
1453             if (handler != null) {
1454                 handler(this, e);
1455             }
1456         }
1457
1458
1459         /// <devdoc>
1460         /// Raises the SendingMail event.
1461         /// </devdoc>
1462         protected virtual void OnSendingMail(MailMessageEventArgs e) {
1463             MailMessageEventHandler handler = (MailMessageEventHandler)Events[EventSendingMail];
1464             if (handler != null) {
1465                 handler(this, e);
1466             }
1467         }
1468
1469         protected virtual void OnSendMailError(SendMailErrorEventArgs e) {
1470             SendMailErrorEventHandler handler = (SendMailErrorEventHandler)Events[EventSendMailError];
1471             if (handler != null) {
1472                 handler(this, e);
1473             }
1474         }
1475
1476
1477         /// <devdoc>
1478         /// Raises the VerifyingUser event.
1479         /// </devdoc>
1480         protected virtual void OnVerifyingUser(LoginCancelEventArgs e) {
1481             LoginCancelEventHandler handler = (LoginCancelEventHandler)Events[EventVerifyingUser];
1482             if (handler != null) {
1483                 handler(this, e);
1484             }
1485         }
1486
1487
1488         /// <devdoc>
1489         /// Called when an event is raised by a control inside one of our templates.  Attempts to send
1490         /// password if the event was raised by the submit button.
1491         /// </devdoc>
1492         protected override bool OnBubbleEvent(object source, EventArgs e) {
1493             bool handled = false;
1494             if (e is CommandEventArgs) {
1495                 CommandEventArgs ce = (CommandEventArgs)e;
1496                 if (ce.CommandName.Equals(SubmitButtonCommandName, StringComparison.CurrentCultureIgnoreCase)) {
1497                     AttemptSendPassword();
1498                     handled = true;
1499                 }
1500             }
1501             return handled;
1502         }
1503
1504
1505         protected internal override void OnInit(EventArgs e) {
1506             base.OnInit(e);
1507             Page.RegisterRequiresControlState(this);
1508             Page.LoadComplete += new EventHandler(OnPageLoadComplete);
1509         }
1510
1511         private void OnPageLoadComplete(object sender, EventArgs e) {
1512             if (CurrentView == View.Question) {
1513                 // Question will be null if the page was posted back using a control outside the
1514                 // PasswordRecovery (VSWhidbey 81302).  Load the Question in Page.LoadComplete instead
1515                 // of Control.OnPreRender(), so that the Question property is available to the page
1516                 // developer earlier in the lifecycle.
1517                 if (String.IsNullOrEmpty(Question)) {
1518                     MembershipProvider provider = LoginUtil.GetProvider(MembershipProvider);
1519                     MembershipUser user = provider.GetUser(UserNameInternal, /*isUserOnline*/ false, /*throwOnError*/ false);
1520                     if (user != null) {
1521                         Question = user.PasswordQuestion;
1522                         if (String.IsNullOrEmpty(Question)) {
1523                             SetFailureTextLabel(_questionContainer, GeneralFailureText);
1524                         }
1525                     }
1526                     else {
1527                         SetFailureTextLabel(_questionContainer, GeneralFailureText);
1528                     }
1529                 }
1530             }
1531         }
1532
1533         /// <devdoc>
1534         /// Overridden to set the editable child control properteries.
1535         /// </devdoc>
1536         protected internal override void OnPreRender(EventArgs e) {
1537             base.OnPreRender(e);
1538
1539             _userNameContainer.Visible = false;
1540             _questionContainer.Visible = false;
1541             _successContainer.Visible = false;
1542             switch (CurrentView) {
1543                 case View.UserName:
1544                     _userNameContainer.Visible = true;
1545                     // Set the editable child control properties here instead of Render, so they get into viewstate
1546                     // for the user template.
1547                     SetUserNameEditableChildProperties();
1548                     break;
1549                 case View.Question:
1550                     _questionContainer.Visible = true;
1551                     break;
1552                 case View.Success:
1553                     _successContainer.Visible = true;
1554                     break;
1555             }
1556         }
1557
1558
1559         /// <devdoc>
1560         /// Raises the UserLookupError event
1561         /// </devdoc>
1562         protected virtual void OnUserLookupError(EventArgs e) {
1563             EventHandler handler = (EventHandler)Events[EventUserLookupError];
1564             if (handler != null) {
1565                 handler(this, e);
1566             }
1567         }
1568
1569         private void PerformSuccessAction() {
1570             string successPageUrl = SuccessPageUrl;
1571             if (!String.IsNullOrEmpty(successPageUrl)) {
1572                 // Microsoft suggested that we should not terminate execution of current page, to give
1573                 // page a chance to cleanup its resources.  This may be less performant though.
1574                 // Microsoft suggested that we need to call ResolveClientUrl before redirecting.
1575                 // Example is this control inside user control, want redirect relative to user control dir.
1576                 Page.Response.Redirect(ResolveClientUrl(successPageUrl), false);
1577             }
1578             else {
1579                 CurrentView = View.Success;
1580             }
1581         }
1582
1583
1584         /// <devdoc>
1585         ///     Adds the ClientID and renders contents, because we don't want the outer <span>.
1586         /// </devdoc>
1587         protected internal override void Render(HtmlTextWriter writer) {
1588             if (Page != null) {
1589                 Page.VerifyRenderingInServerForm(this);
1590             }
1591
1592             EnsureChildControls();
1593
1594             if (DesignMode) {
1595                 // Need to redo this for the designer as there's no PreRender(sigh)
1596                 _userNameContainer.Visible = false;
1597                 _questionContainer.Visible = false;
1598                 _successContainer.Visible = false;
1599                 switch (CurrentView) {
1600                     case View.UserName:
1601                         _userNameContainer.Visible = true;
1602                         break;
1603                     case View.Question:
1604                         _questionContainer.Visible = true;
1605                         break;
1606                     case View.Success:
1607                         _successContainer.Visible = true;
1608                         break;
1609                 }
1610             }
1611
1612             switch (CurrentView) {
1613                 case View.UserName:
1614                     SetUserNameChildProperties();
1615                     break;
1616                 case View.Question:
1617                     SetQuestionChildProperties();
1618                     break;
1619                 case View.Success:
1620                     SetSuccessChildProperties();
1621                     break;
1622             }
1623
1624             RenderContents(writer);
1625         }
1626
1627         /// <devdoc>
1628         /// Saves the control state for those properties that should persist across postbacks
1629         /// even when EnableViewState=false.
1630         /// </devdoc>
1631         protected internal override object SaveControlState() {
1632             object baseState = base.SaveControlState();
1633             if (baseState != null || _currentView != 0 || _userName != null) {
1634                 // Save the int value of the enum (instead of the enum value itself)
1635                 // to save space in ControlState
1636                 object currentViewState = null;
1637                 object userNameState = null;
1638
1639                 if (_currentView != 0) {
1640                     currentViewState = (int)_currentView;
1641                 }
1642                 // Don't save _userName once we have reached the success view (VSWhidbey 81327)
1643                 if (_userName != null && _currentView != View.Success) {
1644                     userNameState = _userName;
1645                 }
1646                 return new Triplet(baseState, currentViewState, userNameState);
1647             }
1648             return null;
1649         }
1650
1651
1652         /// <internalonly/>
1653         /// <devdoc>
1654         ///     Saves the state of the <see cref='System.Web.UI.WebControls.Login'/>.
1655         /// </devdoc>
1656         protected override object SaveViewState() {
1657             object[] myState = new object[_viewStateArrayLength];
1658
1659             myState[0] = base.SaveViewState();
1660             myState[1] = (_submitButtonStyle != null) ? ((IStateManager)_submitButtonStyle).SaveViewState() : null;
1661             myState[2] = (_labelStyle != null) ? ((IStateManager)_labelStyle).SaveViewState() : null;
1662             myState[3] = (_textBoxStyle != null) ? ((IStateManager)_textBoxStyle).SaveViewState() : null;
1663             myState[4] = (_hyperLinkStyle != null) ? ((IStateManager)_hyperLinkStyle).SaveViewState() : null;
1664             myState[5] = (_instructionTextStyle != null) ? ((IStateManager)_instructionTextStyle).SaveViewState() : null;
1665             myState[6] = (_titleTextStyle != null) ? ((IStateManager)_titleTextStyle).SaveViewState() : null;
1666             myState[7] = (_failureTextStyle != null) ? ((IStateManager)_failureTextStyle).SaveViewState() : null;
1667             myState[8] = (_successTextStyle != null) ? ((IStateManager)_successTextStyle).SaveViewState() : null;
1668             myState[9] = (_mailDefinition != null) ? ((IStateManager)_mailDefinition).SaveViewState() : null;
1669             myState[10] = (_validatorTextStyle != null) ? ((IStateManager)_validatorTextStyle).SaveViewState() : null;
1670
1671             for (int i = 0; i < _viewStateArrayLength; i++) {
1672                 if (myState[i] != null) {
1673                     return myState;
1674                 }
1675             }
1676
1677             // More performant to return null than an array of null values
1678             return null;
1679         }
1680
1681         /// <internalonly/>
1682         /// <devdoc>
1683         /// Allows the designer to set the CurrentView, so the different templates can be shown in the designer.
1684         /// </devdoc>
1685         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
1686         protected override void SetDesignModeState(IDictionary data) {
1687             if (data != null) {
1688                 object o = data["CurrentView"];
1689                 if (o != null) {
1690                     CurrentView = (View)o;
1691                 }
1692                 o = data["ConvertToTemplate"];
1693                 if (o != null) {
1694                     _convertingToTemplate = (bool)o;
1695                 }
1696                 o = data["RegionEditing"];
1697                 if (o != null) {
1698                     _renderDesignerRegion = (bool)o;
1699                 }
1700             }
1701         }
1702
1703         /// <devdoc>
1704         /// Used frequently, so extracted into method.
1705         /// </devdoc>
1706         private void SetFailureTextLabel(QuestionContainer container, string failureText) {
1707             ITextControl failureTextLabel = (ITextControl)container.FailureTextLabel;
1708             if (failureTextLabel != null) {
1709                 failureTextLabel.Text = failureText;
1710             }
1711         }
1712
1713         /// <devdoc>
1714         /// Used frequently, so extracted into method.
1715         /// </devdoc>
1716         private void SetFailureTextLabel(UserNameContainer container, string failureText) {
1717             ITextControl failureTextLabel = (ITextControl)container.FailureTextLabel;
1718             if (failureTextLabel != null) {
1719                 failureTextLabel.Text = failureText;
1720             }
1721         }
1722
1723         /// <devdoc>
1724         /// Internal because called from PasswordRecoveryAdapter.
1725         /// </devdoc>
1726         internal void SetQuestionChildProperties() {
1727             SetQuestionCommonChildProperties();
1728             if (QuestionTemplate == null) {
1729                 SetQuestionDefaultChildProperties();
1730             }
1731         }
1732
1733         /// <devdoc>
1734         /// Properties that apply to both default and user templates.
1735         /// </devdoc>
1736         private void SetQuestionCommonChildProperties() {
1737             QuestionContainer container = _questionContainer;
1738
1739             // Clear out the tab index so it doesn't get applied to the tables in the container
1740             Util.CopyBaseAttributesToInnerControl(this, container);
1741
1742             container.ApplyStyle(ControlStyle);
1743
1744             // We need to use UserNameInternal for the DropDownList case where it won't fire a TextChanged for the first item
1745             ITextControl userName = (ITextControl)container.UserName;
1746             if (userName != null) {
1747                 // VSWhidbey 304890 - Encode the user name
1748                 userName.Text = HttpUtility.HtmlEncode(UserNameInternal);
1749             }
1750
1751             ITextControl question = (ITextControl)container.Question;
1752             if (question != null) {
1753                 // VSWhidbey 385802 - Encode the question
1754                 question.Text = HttpUtility.HtmlEncode(Question);
1755             }
1756
1757             ITextControl answerTextBox = (ITextControl)container.AnswerTextBox;
1758             if (answerTextBox != null) {
1759                 answerTextBox.Text = String.Empty;
1760             }
1761         }
1762
1763         /// <devdoc>
1764         /// Properties that apply to only the default template.
1765         /// </devdoc>
1766         private void SetQuestionDefaultChildProperties() {
1767             QuestionContainer container = _questionContainer;
1768
1769             // Need to set the BorderPadding on the BorderTable instead of the LayoutTable, since
1770             // setting it on the LayoutTable would cause all of the controls inside the Login to be
1771             // separated by the BorderPadding amount.
1772             container.BorderTable.CellPadding = BorderPadding;
1773             container.BorderTable.CellSpacing = 0;
1774
1775             Literal title = container.Title;
1776             string titleText = QuestionTitleText;
1777             if (titleText.Length > 0) {
1778                 title.Text = titleText;
1779                 if (_titleTextStyle != null) {
1780                     LoginUtil.SetTableCellStyle(title, TitleTextStyle);
1781                 }
1782                 LoginUtil.SetTableCellVisible(title, true);
1783             }
1784             else {
1785                 LoginUtil.SetTableCellVisible(title, false);
1786             }
1787
1788             Literal instruction = container.Instruction;
1789             string instructionText = QuestionInstructionText;
1790             if (instructionText.Length > 0) {
1791                 instruction.Text = instructionText;
1792                 if (_instructionTextStyle != null) {
1793                     LoginUtil.SetTableCellStyle(instruction, InstructionTextStyle);
1794                 }
1795                 LoginUtil.SetTableCellVisible(instruction, true);
1796             }
1797             else {
1798                 LoginUtil.SetTableCellVisible(instruction, false);
1799             }
1800
1801             Literal userNameLabel = container.UserNameLabel;
1802             string userNameLabelText = UserNameLabelText;
1803             if (userNameLabelText.Length > 0) {
1804                 userNameLabel.Text = userNameLabelText;
1805                 if (_labelStyle != null) {
1806                     LoginUtil.SetTableCellStyle(userNameLabel, LabelStyle);
1807                 }
1808                 userNameLabel.Visible = true;
1809             }
1810             else {
1811                 // DO NOT make the whole table cell invisible, because in some layouts it must exist for things
1812                 // to align correctly.  Uncommon that this property will be empty anyway.
1813                 userNameLabel.Visible = false;
1814             }
1815
1816             // Do not make this control invisible if its text is empty, because it must be present in the created
1817             // template in the designer.  Uncommon that the text will be empty anyway.
1818             Control userName = container.UserName;
1819             if (UserNameInternal.Length > 0) {
1820                 userName.Visible = true;
1821             }
1822             else {
1823                 userName.Visible = false;
1824             }
1825             if (userName is WebControl) ((WebControl)userName).TabIndex = TabIndex;
1826
1827             Literal questionLabel = container.QuestionLabel;
1828             string questionLabelText = QuestionLabelText;
1829             if (questionLabelText.Length > 0) {
1830                 questionLabel.Text = questionLabelText;
1831                 if (_labelStyle != null) {
1832                     LoginUtil.SetTableCellStyle(questionLabel, LabelStyle);
1833                 }
1834                 questionLabel.Visible = true;
1835             }
1836             else {
1837                 // DO NOT make the whole table cell invisible, because in some layouts it must exist for things
1838                 // to align correctly.  Uncommon that this property will be empty anyway.
1839                 questionLabel.Visible = false;
1840             }
1841
1842             // Do not make this control invisible if its text is empty, because it must be present in the created
1843             // template in the designer.  Uncommon that the text will be empty anyway.
1844             Control question = container.Question;
1845             if (Question.Length > 0) {
1846                 question.Visible = true;
1847             }
1848             else {
1849                 question.Visible = false;
1850             }
1851
1852             Literal answerLabel = container.AnswerLabel;
1853             string answerLabelText = AnswerLabelText;
1854             if (answerLabelText.Length > 0) {
1855                 answerLabel.Text = answerLabelText;
1856                 if (_labelStyle != null) {
1857                     LoginUtil.SetTableCellStyle(answerLabel, LabelStyle);
1858                 }
1859                 answerLabel.Visible = true;
1860             }
1861             else {
1862                 // DO NOT make the whole table cell invisible, because in some layouts it must exist for things
1863                 // to align correctly.  Uncommon that this property will be empty anyway.
1864                 answerLabel.Visible = false;
1865             }
1866
1867             WebControl answerTextBox = (WebControl)container.AnswerTextBox;
1868             Debug.Assert(answerTextBox != null, "AnswerTextBox cannot be null for the DefaultTemplate");
1869             if (_textBoxStyle != null) {
1870                 answerTextBox.ApplyStyle(TextBoxStyle);
1871             }
1872             answerTextBox.TabIndex = TabIndex;
1873             answerTextBox.AccessKey = AccessKey;
1874
1875             bool enableValidation = (CurrentView == View.Question);
1876             RequiredFieldValidator answerRequired = container.AnswerRequired;
1877             answerRequired.ErrorMessage = AnswerRequiredErrorMessage;
1878             answerRequired.ToolTip = AnswerRequiredErrorMessage;
1879             answerRequired.Enabled = enableValidation;
1880             answerRequired.Visible = enableValidation;
1881             if (_validatorTextStyle != null) {
1882                 answerRequired.ApplyStyle(_validatorTextStyle);
1883             }
1884
1885             LinkButton linkButton = container.LinkButton;
1886             ImageButton imageButton = container.ImageButton;
1887             Button pushButton = container.PushButton;
1888
1889             WebControl button = null;
1890             switch (SubmitButtonType) {
1891                 case ButtonType.Link:
1892                     linkButton.Text = SubmitButtonText;
1893                     button = linkButton;
1894                     break;
1895                 case ButtonType.Image:
1896                     imageButton.ImageUrl = SubmitButtonImageUrl;
1897                     imageButton.AlternateText = SubmitButtonText;
1898                     button = imageButton;
1899                     break;
1900                 case ButtonType.Button:
1901                     pushButton.Text = SubmitButtonText;
1902                     button = pushButton;
1903                     break;
1904             }
1905
1906             // Set all buttons to nonvisible, then set the selected button to visible
1907             linkButton.Visible = false;
1908             imageButton.Visible = false;
1909             pushButton.Visible = false;
1910             button.Visible = true;
1911             button.TabIndex = TabIndex;
1912
1913             if (_submitButtonStyle != null) {
1914                 button.ApplyStyle(SubmitButtonStyle);
1915             }
1916
1917             HyperLink helpPageLink = container.HelpPageLink;
1918             string helpPageText = HelpPageText;
1919
1920             Image helpPageIcon = container.HelpPageIcon;
1921             if (helpPageText.Length > 0) {
1922                 helpPageLink.Text = helpPageText;
1923                 helpPageLink.NavigateUrl = HelpPageUrl;
1924                 helpPageLink.TabIndex = TabIndex;
1925                 helpPageLink.Visible = true;
1926             }
1927             else {
1928                 helpPageLink.Visible = false;
1929             }
1930
1931             string helpPageIconUrl = HelpPageIconUrl;
1932             bool helpPageIconVisible = (helpPageIconUrl.Length > 0);
1933             helpPageIcon.Visible = helpPageIconVisible;
1934             if (helpPageIconVisible) {
1935                 helpPageIcon.ImageUrl = helpPageIconUrl;
1936                 helpPageIcon.AlternateText = helpPageText;
1937             }
1938
1939             if (helpPageLink.Visible || helpPageIcon.Visible) {
1940                 if (_hyperLinkStyle != null) {
1941                     // Apply style except font to table cell, then apply font and forecolor to HyperLinks
1942                     // VSWhidbey 81289
1943                     TableItemStyle hyperLinkStyleExceptFont = new TableItemStyle();
1944                     hyperLinkStyleExceptFont.CopyFrom(HyperLinkStyle);
1945                     hyperLinkStyleExceptFont.Font.Reset();
1946                     LoginUtil.SetTableCellStyle(helpPageLink, hyperLinkStyleExceptFont);
1947                     helpPageLink.Font.CopyFrom(HyperLinkStyle.Font);
1948                     helpPageLink.ForeColor = HyperLinkStyle.ForeColor;
1949                 }
1950                 LoginUtil.SetTableCellVisible(helpPageLink, true);
1951             }
1952             else {
1953                 LoginUtil.SetTableCellVisible(helpPageLink, false);
1954             }
1955
1956             Control failureTextLabel = container.FailureTextLabel;
1957             if (((ITextControl)failureTextLabel).Text.Length > 0) {
1958                 LoginUtil.SetTableCellStyle(failureTextLabel, FailureTextStyle);
1959                 LoginUtil.SetTableCellVisible(failureTextLabel, true);
1960             }
1961             else {
1962                 LoginUtil.SetTableCellVisible(failureTextLabel, false);
1963             }
1964         }
1965
1966         /// <devdoc>
1967         /// Internal because called from PasswordRecoveryAdapter.
1968         /// </devdoc>
1969         internal void SetSuccessChildProperties() {
1970             SuccessContainer container = _successContainer;
1971
1972             // Clear out the tab index so it doesn't get applied to the tables in the container
1973             Util.CopyBaseAttributesToInnerControl(this, container);
1974
1975             container.ApplyStyle(ControlStyle);
1976
1977             if (SuccessTemplate == null) {
1978                 container.BorderTable.CellPadding = BorderPadding;
1979                 container.BorderTable.CellSpacing = 0;
1980
1981                 Literal successTextLabel = container.SuccessTextLabel;
1982                 string successText = SuccessText;
1983                 if (successText.Length > 0) {
1984                     successTextLabel.Text = successText;
1985                     if (_successTextStyle != null) {
1986                         LoginUtil.SetTableCellStyle(successTextLabel, _successTextStyle);
1987                     }
1988                     LoginUtil.SetTableCellVisible(successTextLabel, true);
1989                 }
1990                 else {
1991                     LoginUtil.SetTableCellVisible(successTextLabel, false);
1992                 }
1993             }
1994         }
1995
1996         /// <devdoc>
1997         /// Internal because called from PasswordRecoveryAdapter.
1998         /// </devdoc>
1999         internal void SetUserNameChildProperties() {
2000             SetUserNameCommonChildProperties();
2001             if (UserNameTemplate == null) {
2002                 SetUserNameDefaultChildProperties();
2003             }
2004         }
2005
2006         /// <devdoc>
2007         /// Properties that apply to both default and user templates.
2008         /// </devdoc>
2009         private void SetUserNameCommonChildProperties() {
2010             // Clear out the tab index so it doesn't get applied to the tables in the container
2011             Util.CopyBaseAttributesToInnerControl(this, _userNameContainer);
2012
2013             _userNameContainer.ApplyStyle(ControlStyle);
2014         }
2015
2016         /// <devdoc>
2017         /// Properties that apply to only the default template.
2018         /// </devdoc>
2019         private void SetUserNameDefaultChildProperties() {
2020             UserNameContainer container = _userNameContainer;
2021             if (UserNameTemplate == null) {
2022                 _userNameContainer.BorderTable.CellPadding = BorderPadding;
2023                 _userNameContainer.BorderTable.CellSpacing = 0;
2024
2025                 Literal title = container.Title;
2026                 string titleText = UserNameTitleText;
2027                 if (titleText.Length > 0) {
2028                     title.Text = titleText;
2029                     if (_titleTextStyle != null) {
2030                         LoginUtil.SetTableCellStyle(title, TitleTextStyle);
2031                     }
2032                     LoginUtil.SetTableCellVisible(title, true);
2033                 }
2034                 else {
2035                     LoginUtil.SetTableCellVisible(title, false);
2036                 }
2037
2038                 Literal instruction = container.Instruction;
2039                 string instructionText = UserNameInstructionText;
2040                 if (instructionText.Length > 0) {
2041                     instruction.Text = instructionText;
2042                     if (_instructionTextStyle != null) {
2043                         LoginUtil.SetTableCellStyle(instruction, InstructionTextStyle);
2044                     }
2045                     LoginUtil.SetTableCellVisible(instruction, true);
2046                 }
2047                 else {
2048                     LoginUtil.SetTableCellVisible(instruction, false);
2049                 }
2050
2051                 Literal userNameLabel = container.UserNameLabel;
2052                 string userNameLabelText = UserNameLabelText;
2053                 if (userNameLabelText.Length > 0) {
2054                     userNameLabel.Text = userNameLabelText;
2055                     if (_labelStyle != null) {
2056                         LoginUtil.SetTableCellStyle(userNameLabel, LabelStyle);
2057                     }
2058                     userNameLabel.Visible = true;
2059                 }
2060                 else {
2061                     // DO NOT make the whole table cell invisible, because in some layouts it must exist for things
2062                     // to align correctly.  Uncommon that this property will be empty anyway.
2063                     userNameLabel.Visible = false;
2064                 }
2065
2066                 WebControl userNameTextBox = (WebControl)container.UserNameTextBox;
2067                 Debug.Assert(userNameTextBox != null, "UserNameTextBox cannot be null for the DefaultTemplate");
2068                 if (_textBoxStyle != null) {
2069                     userNameTextBox.ApplyStyle(TextBoxStyle);
2070                 }
2071                 userNameTextBox.TabIndex = TabIndex;
2072                 userNameTextBox.AccessKey = AccessKey;
2073
2074                 bool enableValidation = (CurrentView == View.UserName);
2075                 RequiredFieldValidator userNameRequired = container.UserNameRequired;
2076                 userNameRequired.ErrorMessage = UserNameRequiredErrorMessage;
2077                 userNameRequired.ToolTip = UserNameRequiredErrorMessage;
2078                 userNameRequired.Enabled = enableValidation;
2079                 userNameRequired.Visible = enableValidation;
2080                 if (_validatorTextStyle != null) {
2081                     userNameRequired.ApplyStyle(_validatorTextStyle);
2082                 }
2083
2084                 LinkButton linkButton = container.LinkButton;
2085                 ImageButton imageButton = container.ImageButton;
2086                 Button pushButton = container.PushButton;
2087
2088                 WebControl button = null;
2089                 switch (SubmitButtonType) {
2090                     case ButtonType.Link:
2091                         linkButton.Text = SubmitButtonText;
2092                         button = linkButton;
2093                         break;
2094                     case ButtonType.Image:
2095                         imageButton.ImageUrl = SubmitButtonImageUrl;
2096                         imageButton.AlternateText = SubmitButtonText;
2097                         button = imageButton;
2098                         break;
2099                     case ButtonType.Button:
2100                         pushButton.Text = SubmitButtonText;
2101                         button = pushButton;
2102                         break;
2103                 }
2104
2105                 // Set all buttons to nonvisible, then set the selected button to visible
2106                 linkButton.Visible = false;
2107                 imageButton.Visible = false;
2108                 pushButton.Visible = false;
2109                 button.Visible = true;
2110                 button.TabIndex = TabIndex;
2111
2112                 if (_submitButtonStyle != null) {
2113                     button.ApplyStyle(SubmitButtonStyle);
2114                 }
2115
2116                 HyperLink helpPageLink = container.HelpPageLink;
2117                 string helpPageText = HelpPageText;
2118
2119                 Image helpPageIcon = container.HelpPageIcon;
2120                 if (helpPageText.Length > 0) {
2121                     helpPageLink.Text = helpPageText;
2122                     helpPageLink.NavigateUrl = HelpPageUrl;
2123                     helpPageLink.Visible = true;
2124                     helpPageLink.TabIndex = TabIndex;
2125                 }
2126                 else {
2127                     helpPageLink.Visible = false;
2128                 }
2129                 string helpPageIconUrl = HelpPageIconUrl;
2130                 bool helpPageIconVisible = (helpPageIconUrl.Length > 0);
2131                 helpPageIcon.Visible = helpPageIconVisible;
2132                 if (helpPageIconVisible) {
2133                     helpPageIcon.ImageUrl = helpPageIconUrl;
2134                     helpPageIcon.AlternateText = helpPageText;
2135                 }
2136
2137                 if (helpPageLink.Visible || helpPageIcon.Visible) {
2138                     if (_hyperLinkStyle != null) {
2139                         // Apply style except font to table cell, then apply font and forecolor to HyperLinks
2140                         // VSWhidbey 81289
2141                         Style hyperLinkStyleExceptFont = new TableItemStyle();
2142                         hyperLinkStyleExceptFont.CopyFrom(HyperLinkStyle);
2143                         hyperLinkStyleExceptFont.Font.Reset();
2144                         LoginUtil.SetTableCellStyle(helpPageLink, hyperLinkStyleExceptFont);
2145                         helpPageLink.Font.CopyFrom(HyperLinkStyle.Font);
2146                         helpPageLink.ForeColor = HyperLinkStyle.ForeColor;
2147                     }
2148                     LoginUtil.SetTableCellVisible(helpPageLink, true);
2149                 }
2150                 else {
2151                     LoginUtil.SetTableCellVisible(helpPageLink, false);
2152                 }
2153
2154                 Control failureTextLabel = container.FailureTextLabel;
2155                 if (((ITextControl)failureTextLabel).Text.Length > 0) {
2156                     LoginUtil.SetTableCellStyle(failureTextLabel, FailureTextStyle);
2157                     LoginUtil.SetTableCellVisible(failureTextLabel, true);
2158                 }
2159                 else {
2160                     LoginUtil.SetTableCellVisible(failureTextLabel, false);
2161                 }
2162             }
2163         }
2164
2165         /// <devdoc>
2166         /// Called from CreateChildControls and PreRender
2167         // - So change events will be raised if viewstate is disabled on the child controls
2168         //   - Viewstate is always disabled for default template, and might be for user template
2169         // - So the controls render correctly in the designer
2170         /// </devdoc>
2171         private void SetUserNameEditableChildProperties() {
2172             // We need to use UserNameInternal for the DropDownList case where it won't fire a TextChanged for the first item
2173             string userName = UserNameInternal;
2174             if (userName.Length > 0) {
2175                 ITextControl userNameTextBox = (ITextControl)_userNameContainer.UserNameTextBox;
2176                 // UserNameTextBox is a required control, but it may be null at design-time
2177                 if (userNameTextBox != null) {
2178                     userNameTextBox.Text = userName;
2179                 }
2180             }
2181         }
2182
2183
2184         /// <devdoc>
2185         /// Marks the starting point to begin tracking and saving changes to the
2186         /// control as part of the control viewstate.
2187         /// </devdoc>
2188         protected override void TrackViewState() {
2189             base.TrackViewState();
2190
2191             if (_submitButtonStyle != null) {
2192                 ((IStateManager)_submitButtonStyle).TrackViewState();
2193             }
2194             if (_labelStyle != null) {
2195                 ((IStateManager)_labelStyle).TrackViewState();
2196             }
2197             if (_textBoxStyle != null) {
2198                 ((IStateManager)_textBoxStyle).TrackViewState();
2199             }
2200             if (_hyperLinkStyle != null) {
2201                 ((IStateManager)_hyperLinkStyle).TrackViewState();
2202             }
2203             if (_instructionTextStyle != null) {
2204                 ((IStateManager)_instructionTextStyle).TrackViewState();
2205             }
2206             if (_titleTextStyle != null) {
2207                 ((IStateManager)_titleTextStyle).TrackViewState();
2208             }
2209             if (_failureTextStyle != null) {
2210                 ((IStateManager)_failureTextStyle).TrackViewState();
2211             }
2212             if (_successTextStyle != null) {
2213                 ((IStateManager)_successTextStyle).TrackViewState();
2214             }
2215             if (_mailDefinition != null) {
2216                 ((IStateManager)_mailDefinition).TrackViewState();
2217             }
2218             if (_validatorTextStyle != null) {
2219                 ((IStateManager)_validatorTextStyle).TrackViewState();
2220             }
2221         }
2222
2223         private void UpdateValidators() {
2224             if (UserNameTemplate == null && _userNameContainer != null) {
2225                 bool enabled = (CurrentView == View.UserName);
2226                 _userNameContainer.UserNameRequired.Enabled = enabled;
2227                 _userNameContainer.UserNameRequired.Visible = enabled;
2228             }
2229             if (QuestionTemplate == null && _questionContainer != null) {
2230                 bool enabled = (CurrentView == View.Question);
2231                 _questionContainer.AnswerRequired.Enabled = enabled;
2232                 _questionContainer.AnswerRequired.Visible = enabled;
2233             }
2234         }
2235
2236         /// <devdoc>
2237         /// Called when the answer text box changes.
2238         /// </devdoc>
2239         private void UserNameTextChanged(object source, EventArgs e) {
2240             UserName = ((ITextControl)source).Text;
2241         }
2242
2243         /// <devdoc>
2244         /// The default question template for the control, used if QuestionTemplate is null.
2245         /// </devdoc>
2246         private sealed class DefaultQuestionTemplate : ITemplate {
2247             private PasswordRecovery _owner;
2248
2249             public DefaultQuestionTemplate(PasswordRecovery owner) {
2250                 _owner = owner;
2251             }
2252
2253             /// <devdoc>
2254             ///  Creates the child controls, sets certain properties (mostly static properties)
2255             /// </devdoc>
2256             private void CreateControls(QuestionContainer questionContainer) {
2257                 string validationGroup = _owner.UniqueID;
2258
2259                 questionContainer.Title = new Literal();
2260                 questionContainer.Instruction = new Literal();
2261                 questionContainer.UserNameLabel = new Literal();
2262                 questionContainer.UserName = new Literal();
2263                 questionContainer.QuestionLabel = new Literal();
2264                 questionContainer.Question = new Literal();
2265
2266                 // Needed for "convert to template" feature
2267                 questionContainer.UserName.ID = _userNameID;
2268                 questionContainer.Question.ID = _questionID;
2269
2270                 TextBox answerTextBox = new TextBox();
2271                 answerTextBox.ID = _answerID;
2272                 questionContainer.AnswerTextBox = answerTextBox;
2273                 questionContainer.AnswerLabel = new LabelLiteral(answerTextBox);
2274
2275                 bool enableValidation = (_owner.CurrentView == View.Question);
2276                 RequiredFieldValidator answerRequired = new RequiredFieldValidator();
2277                 answerRequired.ID = _answerRequiredID;
2278                 answerRequired.ValidationGroup = validationGroup;
2279                 answerRequired.ControlToValidate = answerTextBox.ID;
2280                 answerRequired.Display = _requiredFieldValidatorDisplay;
2281                 answerRequired.Text = SR.GetString(SR.LoginControls_DefaultRequiredFieldValidatorText);
2282                 answerRequired.Enabled = enableValidation;
2283                 answerRequired.Visible = enableValidation;
2284                 questionContainer.AnswerRequired = answerRequired;
2285
2286                 LinkButton linkButton = new LinkButton();
2287                 linkButton.ID = _linkButtonID;
2288                 linkButton.ValidationGroup = validationGroup;
2289                 linkButton.CommandName = SubmitButtonCommandName;
2290                 questionContainer.LinkButton = linkButton;
2291
2292                 ImageButton imageButton = new ImageButton();
2293                 imageButton.ID = _imageButtonID;
2294                 imageButton.ValidationGroup = validationGroup;
2295                 imageButton.CommandName = SubmitButtonCommandName;
2296                 questionContainer.ImageButton = imageButton;
2297
2298                 Button pushButton = new Button();
2299                 pushButton.ID = _pushButtonID;
2300                 pushButton.ValidationGroup = validationGroup;
2301                 pushButton.CommandName = SubmitButtonCommandName;
2302                 questionContainer.PushButton = pushButton;
2303
2304                 questionContainer.HelpPageLink = new HyperLink();
2305                 questionContainer.HelpPageLink.ID = _helpLinkID;
2306                 questionContainer.HelpPageIcon = new Image();
2307
2308                 Literal failureTextLabel = new Literal();
2309                 failureTextLabel.ID = _failureTextID;
2310                 questionContainer.FailureTextLabel = failureTextLabel;
2311             }
2312
2313             /// <devdoc>
2314             /// Adds the controls to a table for layout.  Layout depends on TextLayout.
2315             /// </devdoc>
2316             private void LayoutControls(QuestionContainer questionContainer) {
2317                 LoginTextLayout textLayout = _owner.TextLayout;
2318                 if (textLayout == LoginTextLayout.TextOnLeft) {
2319                     LayoutTextOnLeft(questionContainer);
2320                 }
2321                 else {
2322                     LayoutTextOnTop(questionContainer);
2323                 }
2324             }
2325
2326             private void LayoutTextOnLeft(QuestionContainer questionContainer) {
2327                 Table table = new Table();
2328                 table.CellPadding = 0;
2329                 TableRow r;
2330                 TableCell c;
2331
2332                 r = new LoginUtil.DisappearingTableRow();
2333                 c = new TableCell();
2334                 c.ColumnSpan = 2;
2335                 c.HorizontalAlign = HorizontalAlign.Center;
2336                 c.Controls.Add(questionContainer.Title);
2337                 r.Cells.Add(c);
2338                 table.Rows.Add(r);
2339
2340                 r = new LoginUtil.DisappearingTableRow();
2341                 c = new TableCell();
2342                 c.ColumnSpan = 2;
2343                 c.HorizontalAlign = HorizontalAlign.Center;
2344                 c.Controls.Add(questionContainer.Instruction);
2345                 r.Cells.Add(c);
2346                 table.Rows.Add(r);
2347
2348                 r = new LoginUtil.DisappearingTableRow();
2349                 c = new TableCell();
2350                 c.HorizontalAlign = HorizontalAlign.Right;
2351                 c.Controls.Add(questionContainer.UserNameLabel);
2352                 r.Cells.Add(c);
2353
2354                 c = new TableCell();
2355                 c.Controls.Add(questionContainer.UserName);
2356                 r.Cells.Add(c);
2357                 table.Rows.Add(r);
2358
2359                 r = new LoginUtil.DisappearingTableRow();
2360                 c = new TableCell();
2361                 c.HorizontalAlign = HorizontalAlign.Right;
2362                 c.Controls.Add(questionContainer.QuestionLabel);
2363                 r.Cells.Add(c);
2364
2365                 c = new TableCell();
2366                 c.Controls.Add(questionContainer.Question);
2367                 r.Cells.Add(c);
2368                 table.Rows.Add(r);
2369
2370                 r = new LoginUtil.DisappearingTableRow();
2371                 c = new TableCell();
2372                 c.HorizontalAlign = HorizontalAlign.Right;
2373                 c.Controls.Add(questionContainer.AnswerLabel);
2374                 if (_owner.ConvertingToTemplate) {
2375                     questionContainer.AnswerLabel.RenderAsLabel = true;
2376                 }
2377                 r.Cells.Add(c);
2378
2379                 c = new TableCell();
2380                 c.Controls.Add(questionContainer.AnswerTextBox);
2381                 c.Controls.Add(questionContainer.AnswerRequired);
2382                 r.Cells.Add(c);
2383                 table.Rows.Add(r);
2384
2385                 r = new LoginUtil.DisappearingTableRow();
2386                 c = new TableCell();
2387                 c.ColumnSpan = 2;
2388                 c.HorizontalAlign = HorizontalAlign.Center;
2389                 c.Controls.Add(questionContainer.FailureTextLabel);
2390                 r.Cells.Add(c);
2391                 table.Rows.Add(r);
2392
2393                 r = new LoginUtil.DisappearingTableRow();
2394                 c = new TableCell();
2395                 c.ColumnSpan = 2;
2396                 c.HorizontalAlign = HorizontalAlign.Right;
2397                 c.Controls.Add(questionContainer.LinkButton);
2398                 c.Controls.Add(questionContainer.ImageButton);
2399                 c.Controls.Add(questionContainer.PushButton);
2400                 r.Cells.Add(c);
2401                 table.Rows.Add(r);
2402
2403                 r = new LoginUtil.DisappearingTableRow();
2404                 c = new TableCell();
2405                 c.ColumnSpan = 2;
2406                 c.Controls.Add(questionContainer.HelpPageIcon);
2407                 c.Controls.Add(questionContainer.HelpPageLink);
2408                 r.Cells.Add(c);
2409                 table.Rows.Add(r);
2410
2411                 Table table2 = LoginUtil.CreateChildTable(_owner.ConvertingToTemplate);
2412                 r = new TableRow();
2413                 c = new TableCell();
2414                 c.Controls.Add(table);
2415                 r.Cells.Add(c);
2416                 table2.Rows.Add(r);
2417
2418                 questionContainer.LayoutTable = table;
2419                 questionContainer.BorderTable = table2;
2420                 questionContainer.Controls.Add(table2);
2421             }
2422
2423             private void LayoutTextOnTop(QuestionContainer questionContainer) {
2424                 Table table = new Table();
2425                 table.CellPadding = 0;
2426                 TableRow r;
2427                 TableCell c;
2428
2429                 r = new LoginUtil.DisappearingTableRow();
2430                 c = new TableCell();
2431                 c.HorizontalAlign = HorizontalAlign.Center;
2432                 c.Controls.Add(questionContainer.Title);
2433                 r.Cells.Add(c);
2434                 table.Rows.Add(r);
2435
2436                 r = new LoginUtil.DisappearingTableRow();
2437                 c = new TableCell();
2438                 c.HorizontalAlign = HorizontalAlign.Center;
2439                 c.Controls.Add(questionContainer.Instruction);
2440                 r.Cells.Add(c);
2441                 table.Rows.Add(r);
2442
2443                 r = new LoginUtil.DisappearingTableRow();
2444                 c = new TableCell();
2445                 c.Controls.Add(questionContainer.UserNameLabel);
2446                 r.Cells.Add(c);
2447                 table.Rows.Add(r);
2448
2449                 r = new LoginUtil.DisappearingTableRow();
2450                 c = new TableCell();
2451                 c.Controls.Add(questionContainer.UserName);
2452                 r.Cells.Add(c);
2453                 table.Rows.Add(r);
2454
2455                 r = new LoginUtil.DisappearingTableRow();
2456                 c = new TableCell();
2457                 c.Controls.Add(questionContainer.QuestionLabel);
2458                 r.Cells.Add(c);
2459                 table.Rows.Add(r);
2460
2461                 r = new LoginUtil.DisappearingTableRow();
2462                 c = new TableCell();
2463                 c.Controls.Add(questionContainer.Question);
2464                 r.Cells.Add(c);
2465                 table.Rows.Add(r);
2466
2467                 r = new LoginUtil.DisappearingTableRow();
2468                 c = new TableCell();
2469                 c.Controls.Add(questionContainer.AnswerLabel);
2470                 if (_owner.ConvertingToTemplate) {
2471                     questionContainer.AnswerLabel.RenderAsLabel = true;
2472                 }
2473                 r.Cells.Add(c);
2474                 table.Rows.Add(r);
2475
2476                 r = new LoginUtil.DisappearingTableRow();
2477                 c = new TableCell();
2478                 c.Controls.Add(questionContainer.AnswerTextBox);
2479                 c.Controls.Add(questionContainer.AnswerRequired);
2480                 r.Cells.Add(c);
2481                 table.Rows.Add(r);
2482
2483                 r = new LoginUtil.DisappearingTableRow();
2484                 c = new TableCell();
2485                 c.HorizontalAlign = HorizontalAlign.Center;
2486                 c.Controls.Add(questionContainer.FailureTextLabel);
2487                 r.Cells.Add(c);
2488                 table.Rows.Add(r);
2489
2490                 r = new LoginUtil.DisappearingTableRow();
2491                 c = new TableCell();
2492                 c.HorizontalAlign = HorizontalAlign.Right;
2493                 c.Controls.Add(questionContainer.LinkButton);
2494                 c.Controls.Add(questionContainer.ImageButton);
2495                 c.Controls.Add(questionContainer.PushButton);
2496                 r.Cells.Add(c);
2497                 table.Rows.Add(r);
2498
2499                 r = new LoginUtil.DisappearingTableRow();
2500                 c = new TableCell();
2501                 c.Controls.Add(questionContainer.HelpPageIcon);
2502                 c.Controls.Add(questionContainer.HelpPageLink);
2503                 r.Cells.Add(c);
2504                 table.Rows.Add(r);
2505
2506                 Table table2 = LoginUtil.CreateChildTable(_owner.ConvertingToTemplate);
2507                 r = new TableRow();
2508                 c = new TableCell();
2509                 c.Controls.Add(table);
2510                 r.Cells.Add(c);
2511                 table2.Rows.Add(r);
2512
2513                 questionContainer.LayoutTable = table;
2514                 questionContainer.BorderTable = table2;
2515                 questionContainer.Controls.Add(table2);
2516             }
2517
2518             void ITemplate.InstantiateIn(Control container) {
2519                 QuestionContainer questionContainer = (QuestionContainer)container;
2520                 CreateControls(questionContainer);
2521                 LayoutControls(questionContainer);
2522             }
2523         }
2524
2525         /// <devdoc>
2526         /// The default success template for the control, used if SuccessTemplate is null.
2527         /// </devdoc>
2528         private sealed class DefaultSuccessTemplate : ITemplate {
2529             private PasswordRecovery _owner;
2530
2531             public DefaultSuccessTemplate(PasswordRecovery owner) {
2532                 _owner = owner;
2533             }
2534
2535             private void CreateControls(SuccessContainer successContainer) {
2536                 successContainer.SuccessTextLabel = new Literal();
2537             }
2538
2539             private void LayoutControls(SuccessContainer successContainer) {
2540                 Table table = new Table();
2541                 table.CellPadding = 0;
2542                 TableRow r = new LoginUtil.DisappearingTableRow();
2543                 TableCell c = new TableCell();
2544
2545                 c.Controls.Add(successContainer.SuccessTextLabel);
2546                 r.Cells.Add(c);
2547                 table.Rows.Add(r);
2548
2549                 // Extra table for border padding
2550                 Table table2 = LoginUtil.CreateChildTable(_owner.ConvertingToTemplate);
2551                 r = new TableRow();
2552                 c = new TableCell();
2553                 c.Controls.Add(table);
2554                 r.Cells.Add(c);
2555                 table2.Rows.Add(r);
2556
2557                 successContainer.LayoutTable = table;
2558                 successContainer.BorderTable = table2;
2559                 successContainer.Controls.Add(table2);
2560             }
2561
2562             void ITemplate.InstantiateIn(Control container) {
2563                 SuccessContainer successContainer = (SuccessContainer)container;
2564                 CreateControls(successContainer);
2565                 LayoutControls(successContainer);
2566             }
2567         }
2568
2569         /// <devdoc>
2570         /// The default user name template for the control, used if UserNameTemplate is null.
2571         /// </devdoc>
2572         private sealed class DefaultUserNameTemplate : ITemplate {
2573             private PasswordRecovery _owner;
2574
2575             public DefaultUserNameTemplate(PasswordRecovery owner) {
2576                 _owner = owner;
2577             }
2578
2579             private void CreateControls(UserNameContainer userNameContainer) {
2580                 string validationGroup = _owner.UniqueID;
2581
2582                 userNameContainer.Title = new Literal();
2583                 userNameContainer.Instruction = new Literal();
2584
2585                 TextBox userNameTextBox = new TextBox();
2586                 // Must explicitly set the ID of controls that raise postback events
2587                 userNameTextBox.ID = _userNameID;
2588                 userNameContainer.UserNameTextBox = userNameTextBox;
2589                 userNameContainer.UserNameLabel = new LabelLiteral(userNameTextBox);
2590
2591                 bool enableValidation = (_owner.CurrentView == View.UserName);
2592                 RequiredFieldValidator userNameRequired = new RequiredFieldValidator();
2593                 userNameRequired.ID = _userNameRequiredID;
2594                 userNameRequired.ValidationGroup = validationGroup;
2595                 userNameRequired.ControlToValidate = userNameTextBox.ID;
2596                 userNameRequired.Display = _requiredFieldValidatorDisplay;
2597                 userNameRequired.Text = SR.GetString(SR.LoginControls_DefaultRequiredFieldValidatorText);
2598                 userNameRequired.Enabled = enableValidation;
2599                 userNameRequired.Visible = enableValidation;
2600                 userNameContainer.UserNameRequired = userNameRequired;
2601
2602                 LinkButton linkButton = new LinkButton();
2603                 linkButton.ID = _linkButtonID;
2604                 linkButton.ValidationGroup = validationGroup;
2605                 linkButton.CommandName = SubmitButtonCommandName;
2606                 userNameContainer.LinkButton = linkButton;
2607
2608                 ImageButton imageButton = new ImageButton();
2609                 imageButton.ID = _imageButtonID;
2610                 imageButton.ValidationGroup = validationGroup;
2611                 imageButton.CommandName = SubmitButtonCommandName;
2612                 userNameContainer.ImageButton = imageButton;
2613
2614                 Button pushButton = new Button();
2615                 pushButton.ID = _pushButtonID;
2616                 pushButton.ValidationGroup = validationGroup;
2617                 pushButton.CommandName = SubmitButtonCommandName;
2618                 userNameContainer.PushButton = pushButton;
2619
2620                 userNameContainer.HelpPageLink = new HyperLink();
2621                 userNameContainer.HelpPageLink.ID = _helpLinkID;
2622                 userNameContainer.HelpPageIcon = new Image();
2623
2624                 Literal failureTextLabel = new Literal();
2625                 failureTextLabel.ID = _failureTextID;
2626                 userNameContainer.FailureTextLabel = failureTextLabel;
2627             }
2628
2629             private void LayoutControls(UserNameContainer userNameContainer) {
2630                 LoginTextLayout textLayout = _owner.TextLayout;
2631                 if (textLayout == LoginTextLayout.TextOnLeft) {
2632                     LayoutTextOnLeft(userNameContainer);
2633                 }
2634                 else {
2635                     LayoutTextOnTop(userNameContainer);
2636                 }
2637             }
2638
2639             private void LayoutTextOnLeft(UserNameContainer userNameContainer) {
2640                 Table table = new Table();
2641                 table.CellPadding = 0;
2642                 TableRow r;
2643                 TableCell c;
2644
2645                 r = new LoginUtil.DisappearingTableRow();
2646                 c = new TableCell();
2647                 c.ColumnSpan = 2;
2648                 c.HorizontalAlign = HorizontalAlign.Center;
2649                 c.Controls.Add(userNameContainer.Title);
2650                 r.Cells.Add(c);
2651                 table.Rows.Add(r);
2652
2653                 r = new LoginUtil.DisappearingTableRow();
2654                 c = new TableCell();
2655                 c.ColumnSpan = 2;
2656                 c.HorizontalAlign = HorizontalAlign.Center;
2657                 c.Controls.Add(userNameContainer.Instruction);
2658                 r.Cells.Add(c);
2659                 table.Rows.Add(r);
2660
2661                 r = new LoginUtil.DisappearingTableRow();
2662                 c = new TableCell();
2663                 c.HorizontalAlign = HorizontalAlign.Right;
2664                 c.Controls.Add(userNameContainer.UserNameLabel);
2665                 if (_owner.ConvertingToTemplate) {
2666                     userNameContainer.UserNameLabel.RenderAsLabel = true;
2667                 }
2668                 r.Cells.Add(c);
2669
2670                 c = new TableCell();
2671                 c.Controls.Add(userNameContainer.UserNameTextBox);
2672                 c.Controls.Add(userNameContainer.UserNameRequired);
2673                 r.Cells.Add(c);
2674                 table.Rows.Add(r);
2675
2676                 r = new LoginUtil.DisappearingTableRow();
2677                 c = new TableCell();
2678                 c.ColumnSpan = 2;
2679                 c.HorizontalAlign = HorizontalAlign.Center;
2680                 c.Controls.Add(userNameContainer.FailureTextLabel);
2681                 r.Cells.Add(c);
2682                 table.Rows.Add(r);
2683
2684                 r = new LoginUtil.DisappearingTableRow();
2685                 c = new TableCell();
2686                 c.ColumnSpan = 2;
2687                 c.HorizontalAlign = HorizontalAlign.Right;
2688                 c.Controls.Add(userNameContainer.LinkButton);
2689                 c.Controls.Add(userNameContainer.ImageButton);
2690                 c.Controls.Add(userNameContainer.PushButton);
2691                 r.Cells.Add(c);
2692                 table.Rows.Add(r);
2693
2694                 r = new LoginUtil.DisappearingTableRow();
2695                 c = new TableCell();
2696                 c.ColumnSpan = 2;
2697                 c.Controls.Add(userNameContainer.HelpPageIcon);
2698                 c.Controls.Add(userNameContainer.HelpPageLink);
2699                 r.Cells.Add(c);
2700                 table.Rows.Add(r);
2701
2702                 Table table2 = LoginUtil.CreateChildTable(_owner.ConvertingToTemplate);
2703                 r = new TableRow();
2704                 c = new TableCell();
2705                 c.Controls.Add(table);
2706                 r.Cells.Add(c);
2707                 table2.Rows.Add(r);
2708
2709                 userNameContainer.LayoutTable = table;
2710                 userNameContainer.BorderTable = table2;
2711                 userNameContainer.Controls.Add(table2);
2712             }
2713
2714             private void LayoutTextOnTop(UserNameContainer userNameContainer) {
2715                 Table table = new Table();
2716                 table.CellPadding = 0;
2717                 TableRow r;
2718                 TableCell c;
2719
2720                 r = new LoginUtil.DisappearingTableRow();
2721                 c = new TableCell();
2722                 c.HorizontalAlign = HorizontalAlign.Center;
2723                 c.Controls.Add(userNameContainer.Title);
2724                 r.Cells.Add(c);
2725                 table.Rows.Add(r);
2726
2727                 r = new LoginUtil.DisappearingTableRow();
2728                 c = new TableCell();
2729                 c.HorizontalAlign = HorizontalAlign.Center;
2730                 c.Controls.Add(userNameContainer.Instruction);
2731                 r.Cells.Add(c);
2732                 table.Rows.Add(r);
2733
2734                 r = new LoginUtil.DisappearingTableRow();
2735                 c = new TableCell();
2736                 c.Controls.Add(userNameContainer.UserNameLabel);
2737                 if (_owner.ConvertingToTemplate) {
2738                     userNameContainer.UserNameLabel.RenderAsLabel = true;
2739                 }
2740                 r.Cells.Add(c);
2741                 table.Rows.Add(r);
2742
2743                 r = new LoginUtil.DisappearingTableRow();
2744                 c = new TableCell();
2745                 c.Controls.Add(userNameContainer.UserNameTextBox);
2746                 c.Controls.Add(userNameContainer.UserNameRequired);
2747                 r.Cells.Add(c);
2748                 table.Rows.Add(r);
2749
2750                 r = new LoginUtil.DisappearingTableRow();
2751                 c = new TableCell();
2752                 c.HorizontalAlign = HorizontalAlign.Center;
2753                 c.Controls.Add(userNameContainer.FailureTextLabel);
2754                 r.Cells.Add(c);
2755                 table.Rows.Add(r);
2756
2757                 r = new LoginUtil.DisappearingTableRow();
2758                 c = new TableCell();
2759                 c.HorizontalAlign = HorizontalAlign.Right;
2760                 c.Controls.Add(userNameContainer.LinkButton);
2761                 c.Controls.Add(userNameContainer.ImageButton);
2762                 c.Controls.Add(userNameContainer.PushButton);
2763                 r.Cells.Add(c);
2764                 table.Rows.Add(r);
2765
2766                 r = new LoginUtil.DisappearingTableRow();
2767                 c = new TableCell();
2768                 c.Controls.Add(userNameContainer.HelpPageIcon);
2769                 c.Controls.Add(userNameContainer.HelpPageLink);
2770                 r.Cells.Add(c);
2771                 table.Rows.Add(r);
2772
2773                 Table table2 = LoginUtil.CreateChildTable(_owner.ConvertingToTemplate);
2774                 r = new TableRow();
2775                 c = new TableCell();
2776                 c.Controls.Add(table);
2777                 r.Cells.Add(c);
2778                 table2.Rows.Add(r);
2779
2780                 userNameContainer.LayoutTable = table;
2781                 userNameContainer.BorderTable = table2;
2782                 userNameContainer.Controls.Add(table2);
2783             }
2784
2785             void ITemplate.InstantiateIn(Control container) {
2786                 UserNameContainer userNameContainer = (UserNameContainer)container;
2787                 CreateControls(userNameContainer);
2788                 LayoutControls(userNameContainer);
2789             }
2790         }
2791
2792
2793         /// <devdoc>
2794         ///     Container for the question template.  Contains properties that reference each child control.
2795         ///     For the default template, the properties are set when the child controls are created.
2796         ///     For the user template, the controls are looked up dynamically by ID.  Some controls are required,
2797         ///     and an exception is thrown if they are missing.  Other controls are optional, and an exception is
2798         ///     thrown if they have the wrong type.
2799         ///     Internal instead of private because it must be used by PasswordRecoveryAdapter.
2800         /// </devdoc>
2801         internal sealed class QuestionContainer : LoginUtil.GenericContainer<PasswordRecovery>, INonBindingContainer {
2802             private LabelLiteral _answerLabel;
2803             private RequiredFieldValidator _answerRequired;
2804             private Control _answerTextBox;
2805             private Control _failureTextLabel;
2806             private HyperLink _helpPageLink;
2807             private Image _helpPageIcon;
2808             private ImageButton _imageButton;
2809             private Literal _instruction;
2810             private LinkButton _linkButton;
2811             private Button _pushButton;
2812             private Control _question;
2813             private Literal _questionLabel;
2814             private Literal _title;
2815             private Literal _userNameLabel;
2816             private Control _userName;
2817
2818             public QuestionContainer(PasswordRecovery owner) : base(owner) {
2819             }
2820
2821             public LabelLiteral AnswerLabel {
2822                 get {
2823                     return _answerLabel;
2824                 }
2825                 set {
2826                     _answerLabel = value;
2827                 }
2828             }
2829
2830             public RequiredFieldValidator AnswerRequired {
2831                 get {
2832                     return _answerRequired;
2833                 }
2834
2835                 set {
2836                     _answerRequired = value;
2837                 }
2838             }
2839
2840             public Control AnswerTextBox {
2841                 get {
2842                     if (_answerTextBox != null) {
2843                         return _answerTextBox;
2844                     }
2845                     else {
2846                         return FindRequiredControl<IEditableTextControl>(_answerID, SR.PasswordRecovery_NoAnswerTextBox);
2847                     }
2848                 }
2849                 set {
2850                     _answerTextBox = value;
2851                 }
2852             }
2853
2854             protected override bool ConvertingToTemplate {
2855                 get {
2856                     return Owner.ConvertingToTemplate;
2857                 }
2858             }
2859
2860             public Control FailureTextLabel {
2861                 get {
2862                     if (_failureTextLabel != null) {
2863                         return _failureTextLabel;
2864                     }
2865                     else {
2866                         return FindOptionalControl<ITextControl>(_failureTextID);
2867                     }
2868                 }
2869                 set {
2870                     _failureTextLabel = value;
2871                 }
2872             }
2873
2874             public Image HelpPageIcon {
2875                 get {
2876                     return _helpPageIcon;
2877                 }
2878                 set {
2879                     _helpPageIcon = value;
2880                 }
2881             }
2882
2883             public HyperLink HelpPageLink {
2884                 get {
2885                     return _helpPageLink;
2886                 }
2887                 set {
2888                     _helpPageLink = value;
2889                 }
2890             }
2891
2892             public ImageButton ImageButton {
2893                 get {
2894                     return _imageButton;
2895                 }
2896                 set {
2897                     _imageButton = value;
2898                 }
2899             }
2900
2901             public Literal Instruction {
2902                 get {
2903                     return _instruction;
2904                 }
2905                 set {
2906                     _instruction = value;
2907                 }
2908             }
2909
2910             public LinkButton LinkButton {
2911                 get {
2912                     return _linkButton;
2913                 }
2914                 set {
2915                     _linkButton = value;
2916                 }
2917             }
2918
2919             public Button PushButton {
2920                 get {
2921                     return _pushButton;
2922                 }
2923                 set {
2924                     _pushButton = value;
2925                 }
2926             }
2927
2928             public Control Question {
2929                 get {
2930                     if (_question != null) {
2931                         return _question;
2932                     }
2933                     else {
2934                         return FindOptionalControl<ITextControl>(_questionID);
2935                     }
2936                 }
2937                 set {
2938                     _question = value;
2939                 }
2940             }
2941
2942             public Literal QuestionLabel {
2943                 get {
2944                     return _questionLabel;
2945                 }
2946                 set {
2947                     _questionLabel = value;
2948                 }
2949             }
2950
2951             public Literal Title {
2952                 get {
2953                     return _title;
2954                 }
2955                 set {
2956                     _title = value;
2957                 }
2958             }
2959
2960             public Control UserName {
2961                 get {
2962                     if (_userName != null) {
2963                         return _userName;
2964                     }
2965                     else {
2966                         return FindOptionalControl<ITextControl>(_userNameID);
2967                     }
2968                 }
2969                 set {
2970                     _userName = value;
2971                 }
2972             }
2973
2974             public Literal UserNameLabel {
2975                 get {
2976                     return _userNameLabel;
2977                 }
2978                 set {
2979                     _userNameLabel = value;
2980                 }
2981             }
2982         }
2983
2984         /// <devdoc>
2985         ///     Container for the success template.
2986         ///     Internal instead of private because it must be used by PasswordRecoveryAdapter.
2987         /// </devdoc>
2988         internal sealed class SuccessContainer : LoginUtil.GenericContainer<PasswordRecovery>, INonBindingContainer {
2989             private Literal _successTextLabel;
2990
2991             public SuccessContainer(PasswordRecovery owner) : base(owner) {
2992             }
2993
2994             protected override bool ConvertingToTemplate {
2995                 get {
2996                     return Owner.ConvertingToTemplate;
2997                 }
2998             }
2999
3000             public Literal SuccessTextLabel {
3001                 get {
3002                     return _successTextLabel;
3003                 }
3004                 set {
3005                     _successTextLabel = value;
3006                 }
3007             }
3008         }
3009
3010         /// <devdoc>
3011         ///     Container for the user name template.  Contains properties that reference each child control.
3012         ///     For the default template, the properties are set when the child controls are created.
3013         ///     For the user template, the controls are looked up dynamically by ID.  Some controls are required,
3014         ///     and an exception is thrown if they are missing.  Other controls are optional, and an exception is
3015         ///     thrown if they have the wrong type.
3016         ///     Internal instead of private because it must be used by PasswordRecoveryAdapter.
3017         /// </devdoc>
3018         internal sealed class UserNameContainer : LoginUtil.GenericContainer<PasswordRecovery>, INonBindingContainer {
3019             private Control _failureTextLabel;
3020             private Image _helpPageIcon;
3021             private HyperLink _helpPageLink;
3022             private ImageButton _imageButton;
3023             private Literal _instruction;
3024             private LinkButton _linkButton;
3025             private Button _pushButton;
3026             private Literal _title;
3027             private LabelLiteral _userNameLabel;
3028             private RequiredFieldValidator _userNameRequired;
3029             private Control _userNameTextBox;
3030
3031             public UserNameContainer(PasswordRecovery owner) : base(owner) {
3032             }
3033
3034             protected override bool ConvertingToTemplate {
3035                 get {
3036                     return Owner.ConvertingToTemplate;
3037                 }
3038             }
3039
3040             public Control FailureTextLabel {
3041                 get {
3042                     if (_failureTextLabel != null) {
3043                         return _failureTextLabel;
3044                     }
3045                     else {
3046                         return FindOptionalControl<ITextControl>(_failureTextID);
3047                     }
3048                 }
3049                 set {
3050                     _failureTextLabel = value;
3051                 }
3052             }
3053
3054             public Image HelpPageIcon {
3055                 get {
3056                     return _helpPageIcon;
3057                 }
3058                 set {
3059                     _helpPageIcon = value;
3060                 }
3061             }
3062
3063             public HyperLink HelpPageLink {
3064                 get {
3065                     return _helpPageLink;
3066                 }
3067                 set {
3068                     _helpPageLink = value;
3069                 }
3070             }
3071
3072             public ImageButton ImageButton {
3073                 get {
3074                     return _imageButton;
3075                 }
3076                 set {
3077                     _imageButton = value;
3078                 }
3079             }
3080
3081             public Literal Instruction {
3082                 get {
3083                     return _instruction;
3084                 }
3085                 set {
3086                     _instruction = value;
3087                 }
3088             }
3089
3090             public LinkButton LinkButton {
3091                 get {
3092                     return _linkButton;
3093                 }
3094                 set {
3095                     _linkButton = value;
3096                 }
3097             }
3098
3099             public Button PushButton {
3100                 get {
3101                     return _pushButton;
3102                 }
3103                 set {
3104                     _pushButton = value;
3105                 }
3106             }
3107
3108             public Literal Title {
3109                 get {
3110                     return _title;
3111                 }
3112                 set {
3113                     _title = value;
3114                 }
3115             }
3116
3117             public LabelLiteral UserNameLabel {
3118                 get {
3119                     return _userNameLabel;
3120                 }
3121                 set {
3122                     _userNameLabel = value;
3123                 }
3124             }
3125
3126             public RequiredFieldValidator UserNameRequired {
3127                 get {
3128                     return _userNameRequired;
3129                 }
3130
3131                 set {
3132                     _userNameRequired = value;
3133                 }
3134             }
3135
3136             public Control UserNameTextBox {
3137                 get {
3138                     if (_userNameTextBox != null) {
3139                         return _userNameTextBox;
3140                     }
3141                     else {
3142                         return FindRequiredControl<IEditableTextControl>(_userNameID, SR.PasswordRecovery_NoUserNameTextBox);
3143                     }
3144                 }
3145                 set {
3146                     _userNameTextBox = value;
3147                 }
3148             }
3149         }
3150
3151         /// <devdoc>
3152         /// Internal because used from PasswordRecoveryAdapter
3153         /// </devdoc>
3154         internal enum View {
3155             UserName,
3156             Question,
3157             Success
3158         }
3159     }
3160 }