File: UI\WebControls\LoginView.cs
Project: ndp\fx\src\xsp\system\Web\System.Web.csproj (System.Web)
//------------------------------------------------------------------------------
// <copyright file="LoginView.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
 
namespace System.Web.UI.WebControls {
 
    using System.Collections;
    using System.ComponentModel;
    using System.Security.Permissions;
    using System.Security.Principal;
    using System.Web.Security;
    using System.Web.UI;
 
 
    /// <devdoc>
    /// Renders exactly one of its templates, chosen by whether a user is logged in
    /// and the roles that contain the user.
    /// </devdoc>
    [
    Bindable(false),
    ParseChildren(true),
    PersistChildren(false),
    Designer("System.Web.UI.Design.WebControls.LoginViewDesigner," + AssemblyRef.SystemDesign),
    DefaultProperty("CurrentView"),
    DefaultEvent("ViewChanged"),
    Themeable(true),
    ]
    public class LoginView : Control, INamingContainer {
 
        private RoleGroupCollection _roleGroups;
        private ITemplate _loggedInTemplate;
        private ITemplate _anonymousTemplate;
 
        private int _templateIndex;
 
        private const int anonymousTemplateIndex = 0;
        private const int loggedInTemplateIndex = 1;
        private const int roleGroupStartingIndex = 2;
 
        private static readonly object EventViewChanging = new object();
        private static readonly object EventViewChanged = new object();
 
 
        /// <devdoc>
        /// Template shown when no user is logged in.
        /// </devdoc>
        [
        Browsable(false),
        DefaultValue(null),
        PersistenceMode(PersistenceMode.InnerProperty),
        TemplateContainer(typeof(LoginView)),
        ]
        public virtual ITemplate AnonymousTemplate {
            get {
                return _anonymousTemplate;
            }
            set {
                _anonymousTemplate = value;
            }
        }
 
        [
        Browsable(true),
        ]
        public override bool EnableTheming {
            get {
                return base.EnableTheming;
            }
            set {
                base.EnableTheming = value;
            }
        }
 
        [
        Browsable(true),
        ]
        public override string SkinID {
            get {
                return base.SkinID;
            }
            set {
                base.SkinID = value;
            }
        }
 
 
 
        /// <devdoc>
        /// Copied from CompositeControl.  This control does not extend CompositeControl because it should not be a WebControl.
        /// </devdoc>
        public override ControlCollection Controls {
            get {
                EnsureChildControls();
                return base.Controls;
            }
        }
 
 
        /// <devdoc>
        /// Copied from CompositeControl.  This control does not extend CompositeControl because it should not be a WebControl.
        /// Does not call Base.DataBind(), since we need to call EnsureChildControls() between
        /// OnDataBinding() and DataBindChildren().
        /// </devdoc>
        public override void DataBind() {
            // Do our own databinding
            OnDataBinding(EventArgs.Empty);
 
            EnsureChildControls();
 
            // Do all of our children's databinding
            DataBindChildren();
        }
 
 
        /// <devdoc>
        /// Template shown when a user is logged in, but the user is not in any role associated with a template.
        /// </devdoc>
        [
        Browsable(false),
        DefaultValue(null),
        PersistenceMode(PersistenceMode.InnerProperty),
        TemplateContainer(typeof(LoginView)),
        ]
        public virtual ITemplate LoggedInTemplate {
            get {
                return _loggedInTemplate;
            }
            set {
                _loggedInTemplate = value;
            }
        }
 
 
        /// <devdoc>
        /// Maps groups of roles to templates.
        /// </devdoc>
        [
        WebCategory("Behavior"),
        MergableProperty(false),
        Themeable(false),
        Filterable(false),
        PersistenceMode(PersistenceMode.InnerProperty),
        WebSysDescription(SR.LoginView_RoleGroups)
        ]
        public virtual RoleGroupCollection RoleGroups {
            get {
                if (_roleGroups == null) {
                    _roleGroups = new RoleGroupCollection();
                }
                return _roleGroups;
            }
        }
 
        /// <devdoc>
        /// Index of the template rendered on the previous page load.  Saved in ControlState.
        /// 0:   AnonymousTemplate
        /// 1:   LoggedInTemplate
        /// >=2: RoleGroup template with index n-2
        /// </devdoc>
        private int TemplateIndex {
            get {
                return _templateIndex;
            }
            set {
                if (value != TemplateIndex) {
                    OnViewChanging(EventArgs.Empty);
                    _templateIndex = value;
                    ChildControlsCreated = false;
                    OnViewChanged(EventArgs.Empty);
                }
            }
        }
 
 
        /// <devdoc>
        /// Raised after the view is changed.
        /// </devdoc>
        [
        WebCategory("Action"),
        WebSysDescription(SR.LoginView_ViewChanged)
        ]
        public event EventHandler ViewChanged {
            add {
                Events.AddHandler(EventViewChanged, value);
            }
            remove {
                Events.RemoveHandler(EventViewChanged, value);
            }
        }
 
 
        /// <devdoc>
        /// Raised before the view is changed.  Not cancellable, because the view is changed
        /// when the logged-in user changes, and it wouldn't make sense to cancel this.
        /// </devdoc>
        [
        WebCategory("Action"),
        WebSysDescription(SR.LoginView_ViewChanging)
        ]
        public event EventHandler ViewChanging {
            add {
                Events.AddHandler(EventViewChanging, value);
            }
            remove {
                Events.RemoveHandler(EventViewChanging, value);
            }
        }
 
 
        /// <devdoc>
        /// Instantiate the appropriate template.
        /// </devdoc>
        protected internal override void CreateChildControls() {
            Controls.Clear();
 
            // For the first request, set _templateIndex now, so the correct template is
            // instantiated and we do not raise the ViewChanging/ViewChanged events.
            Page page = Page;
            if (page != null && !page.IsPostBack && !DesignMode) {
                _templateIndex = GetTemplateIndex();
            }
 
            int templateIndex = TemplateIndex;
            ITemplate template = null;
            switch (templateIndex) {
                case anonymousTemplateIndex:
                    template = AnonymousTemplate;
                    break;
                case loggedInTemplateIndex:
                    template = LoggedInTemplate;
                    break;
                default:
                    int roleGroupIndex = templateIndex - roleGroupStartingIndex;
                    RoleGroupCollection roleGroups = RoleGroups;
                    if (0 <= roleGroupIndex && roleGroupIndex < roleGroups.Count) {
                        template = roleGroups[roleGroupIndex].ContentTemplate;
                    }
                    break;
            }
 
            if (template != null) {
                Control templateContainer = new Control();
                template.InstantiateIn(templateContainer);
                Controls.Add(templateContainer);
            }
        }
 
        [
        EditorBrowsable(EditorBrowsableState.Never),
        ]
        public override void Focus() {
            throw new NotSupportedException(SR.GetString(SR.NoFocusSupport, this.GetType().Name));
        }
 
        /// <devdoc>
        /// Loads the control state for those properties that should persist across postbacks
        /// even when EnableViewState=false.
        /// </devdoc>
        protected internal override void LoadControlState(object savedState) {
            if (savedState != null) {
                Pair state = (Pair)savedState;
                if (state.First != null) {
                    base.LoadControlState(state.First);
                }
                if (state.Second != null) {
                    _templateIndex = (int)state.Second;
                }
            }
        }
 
 
        protected internal override void OnInit(EventArgs e) {
            base.OnInit(e);
            if (Page != null) {
                Page.RegisterRequiresControlState(this);
            }
        }
 
 
        /// <devdoc>
        /// Sets the TemplateIndex based on the current user.
        /// </devdoc>
        protected internal override void OnPreRender(EventArgs e) {
            base.OnPreRender(e);
 
            TemplateIndex = GetTemplateIndex();
 
            // This is called in Control.PreRenderRecursiveInteral, but we need to call it again
            // since we may have changed the TemplateIndex
            EnsureChildControls();
        }
 
 
        /// <devdoc>
        /// Raises the ViewChanged event.
        /// </devdoc>
        protected virtual void OnViewChanged(EventArgs e) {
            EventHandler handler = (EventHandler)Events[EventViewChanged];
            if (handler != null) {
                handler(this, e);
            }
        }
 
 
        /// <devdoc>
        /// Raises the ViewChanging event.
        /// </devdoc>
        protected virtual void OnViewChanging(EventArgs e) {
            EventHandler handler = (EventHandler)Events[EventViewChanging];
            if (handler != null) {
                handler(this, e);
            }
        }
 
        protected internal override void Render(HtmlTextWriter writer) {
            EnsureChildControls();
            base.Render(writer);
        }
 
        /// <devdoc>
        /// Saves the control state for those properties that should persist across postbacks
        /// even when EnableViewState=false.
        /// </devdoc>
        protected internal override object SaveControlState() {
            object baseState = base.SaveControlState();
            if (baseState != null || _templateIndex != 0) {
                object templateIndexState = null;
 
                if (_templateIndex != 0) {
                    templateIndexState = _templateIndex;
                }
                return new Pair(baseState, templateIndexState);
            }
            return null;
        }
 
 
        /// <devdoc>
        /// Allows the designer to set the TemplateIndex, so the different templates can be shown in the designer.
        /// </devdoc>
        [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
        protected override void SetDesignModeState(IDictionary data) {
            if (data != null) {
                object o = data["TemplateIndex"];
                if (o != null) {
                    TemplateIndex = (int)o;
 
                    // Note: we always recreate the child controls in the designer to correctly handle the case of
                    // the currently selected role group being deleted.  This is necessary because the
                    // setter for TemplateIndex won't recreate the controls if the TemplateIndex is unchanged,
                    // which is the case when deleting all but the last role group. [Fix for Bug 148406]
                    ChildControlsCreated = false;
                }
            }
        }
 
        private int GetTemplateIndex() {
            if (!DesignMode && Page != null && Page.Request.IsAuthenticated) {
                IPrincipal user = LoginUtil.GetUser(this);
                int roleGroupIndex = -1;
 
                // Unlikely but possible for Page.Request.IsAuthenticated to be true and
                // user to be null.
                if (user != null) {
                    roleGroupIndex = RoleGroups.GetMatchingRoleGroupInternal(user);
                }
 
                if (roleGroupIndex >= 0) {
                    return roleGroupIndex + roleGroupStartingIndex;
                }
                else {
                    return loggedInTemplateIndex;
                }
            }
            else {
                return anonymousTemplateIndex;
            }
        }
    }
}