File: UI\MobileControls\Form.cs
Project: ndp\fx\src\mit\System\Web\System.Web.Mobile.csproj (System.Web.Mobile)
//------------------------------------------------------------------------------
// <copyright file="Form.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
using System.Web.Mobile;
using System.Web.UI;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Globalization;
using System.Security.Permissions;
 
namespace System.Web.UI.MobileControls
{
    /// <include file='doc\Form.uex' path='docs/doc[@for="Form"]/*' />
    [
        ControlBuilderAttribute(typeof(FormControlBuilder)),
        DefaultEvent("Activate"),
        Designer(typeof(System.Web.UI.Design.MobileControls.FormDesigner)),
        DesignerAdapter(typeof(System.Web.UI.MobileControls.Adapters.HtmlFormAdapter)),
        PersistChildren(true),
        ToolboxData("<{0}:Form runat=\"server\"></{0}:Form>"),
        ToolboxItem("System.Web.UI.Design.WebControlToolboxItem, " + AssemblyRef.SystemDesign)
    ]
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)]
    [Obsolete("The System.Web.Mobile.dll assembly has been deprecated and should no longer be used. For information about how to develop ASP.NET mobile applications, see http://go.microsoft.com/fwlink/?LinkId=157231.")]
    public class Form : Panel, ITemplateable, IPostBackEventHandler
    {
 
        private static readonly Object EventActivate         = new Object();
        private static readonly Object EventDeactivate       = new Object();
        private static readonly Object EventPaginated        = new Object();
 
        private PagerStyle _pagerStyle;
        private int _cachedCurrentPage = -1;
        private Panel _headerContainer = null;
        private Panel _footerContainer = null;
        private Panel _scriptContainer = null;
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Form"]/*' />
        public Form()
        {
            _pagerStyle = new PagerStyle();
            _pagerStyle.SetControl(this);
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Title"]/*' />
        /// <summary>
        /// <para>
        /// Gets or sets the title used to identify the form.
        /// </para>
        /// </summary>
        /// <value>
        /// <para>
        /// The title may be rendered as part of the form, on devices
        /// that support a title separate from page content (e.g., on
        /// the title bar of a browser using the title tag in HTML).
        /// </para>
        /// </value>
        [
            Bindable(true),
            DefaultValue(""),
            MobileCategory(SR.Category_Appearance),
            MobileSysDescription(SR.Form_Title)
        ]
        public String Title
        {
            get
            {
                String s = (String) ViewState["Title"];
                return((s != null) ? s : String.Empty);
            }
            set
            {
                ViewState["Title"] = value;
            }
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Method"]/*' />
        [
            Bindable(true),
            DefaultValue(FormMethod.Post),
            MobileCategory(SR.Category_Behavior),
            MobileSysDescription(SR.Form_Method)
        ]
        public FormMethod Method
        {
            get
            {
                Object o = ViewState["Method"];
                return ((o != null) ? (FormMethod)o : FormMethod.Post);
            }
            set
            {
                ViewState["Method"] = value;
            }
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Action"]/*' />
        [
            Bindable(true),
            DefaultValue(""),
            Editor(typeof(System.Web.UI.Design.UrlEditor),
                typeof(System.Drawing.Design.UITypeEditor)),
            MobileCategory(SR.Category_Behavior),
            MobileSysDescription(SR.Form_Action)
        ]
        public String Action
        {
            get
            {
                String s = (String) ViewState["Action"];
                return((s != null) ? s : String.Empty);
            }
            set
            {
                ViewState["Action"] = value;
            }
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.PagerStyle"]/*' />
        [
            DefaultValue(null),
            DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
            MobileCategory(SR.Category_Style),
            MobileSysDescription(SR.Form_PagerStyle),
            NotifyParentProperty(true)
        ]
        public PagerStyle PagerStyle
        {
            get
            {
                return _pagerStyle;
            }
        }
 
        /// <internalonly/>
        protected void RaisePostBackEvent(String eventArgument)
        {
            // If the event argument is all numeric, then it's a pager event.
 
            bool notANumber = false;
            int length = eventArgument.Length;
            for (int i = 0; i < length; i++)
            {
                char c = eventArgument[i];
                if (c < '0' || c > '9')
                {
                    notANumber = true;
                    break;
                }
            }
 
            if (!notANumber && length > 0)
            {
                try
                {
                    int page = Int32.Parse(eventArgument, CultureInfo.InvariantCulture);
                    if (page > 0)
                    {
                        int oldPage = _currentPage;
                        if(_cachedCurrentPage == -1)
                        {
                            _currentPage = page;
                            _cachedCurrentPage = page;
                        }
 
                        // currentpage may != page if page is invalid
                        OnPageChange(oldPage, _currentPage);
                    }
                    return;
                }
                catch
                {
                    // Argument may be invalid number, so let adapter handle it.
                }
            }
 
            Adapter.HandlePostBackEvent(eventArgument);
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Activate"]/*' />
        [
            MobileCategory(SR.Category_Action),
            MobileSysDescription(SR.Form_OnActivate)
        ]
        public event EventHandler Activate
        {
            add
            {
                Events.AddHandler(EventActivate, value);
            }
            remove
            {
                Events.RemoveHandler(EventActivate, value);
            }
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Deactivate"]/*' />
        [
            MobileCategory(SR.Category_Action),
            MobileSysDescription(SR.Form_OnDeactivate)
        ]
        public event EventHandler Deactivate
        {
            add
            {
                Events.AddHandler(EventDeactivate, value);
            }
            remove
            {
                Events.RemoveHandler(EventDeactivate, value);
            }
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Paginated"]/*' />
        [
            MobileCategory(SR.Category_Action),
            MobileSysDescription(SR.Form_OnPaginated)
        ]
        public event EventHandler Paginated
        {
            add
            {
                Events.AddHandler(EventPaginated, value);
            }
            remove
            {
                Events.RemoveHandler(EventPaginated, value);
            }
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Header"]/*' />
        [
            Bindable(false),
            Browsable(false),
            DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public Panel Header
        {
            get
            {
                return _headerContainer;
            }
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Footer"]/*' />
        [
            Bindable(false),
            Browsable(false),
            DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public Panel Footer
        {
            get
            {
                return _footerContainer;
            }
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Script"]/*' />
        [
            Bindable(false),
            Browsable(false),
            DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public Panel Script
        {
            get
            {
                return _scriptContainer;
            }
        }
 
        internal bool Activated = false;
 
        internal void FireActivate(EventArgs e)
        {
            if (!Activated)
            {
                Activated = true;
                OnActivate(e);
            }
        }
 
        internal void FireDeactivate(EventArgs e)
        {
            if (Activated)
            {
                Activated = false;
                OnDeactivate(e);
            }
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.OnActivate"]/*' />
        protected virtual void OnActivate(EventArgs e)
        {
            EventHandler onActivate = (EventHandler)Events[EventActivate];
            if (onActivate != null)
            {
                onActivate(this, e);
            }
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.OnDeactivate"]/*' />
        protected virtual void OnDeactivate(EventArgs e)
        {
            EventHandler onDeactivate = (EventHandler)Events[EventDeactivate];
            if (onDeactivate != null)
            {
                onDeactivate(this, e);
            }
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.HasActivateHandler"]/*' />
        public virtual bool HasActivateHandler()
        {
            return Events[EventActivate] != null;
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.HasDeactivateHandler"]/*' />
        public virtual bool HasDeactivateHandler()
        {
            return Events[EventDeactivate] != null;
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.OnPaginated"]/*' />
        protected virtual void OnPaginated(EventArgs e)
        {
            EventHandler onPaginated = (EventHandler)Events[EventPaginated];
            if (onPaginated != null)
            {
                onPaginated(this, e);
            }
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.OnInit"]/*' />
        protected override void OnInit(EventArgs e)
        {
            if (MobilePage != null && !MobilePage.DesignMode)
            {
                // Be sure we're not included in any other Forms.
                for (Control control = this.Parent; control != null; control = control.Parent)
                {
                    Form parentForm = control as Form;
                    if (parentForm != null)
                    {
                        throw new Exception(SR.GetString(SR.Form_NestedForms,
                            this.ID,
                            parentForm.ID));
                    }
                }
            }
            
            base.OnInit(e);
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.GetLinkedForms"]/*' />
        public IList GetLinkedForms(int optimumPageWeight)
        {
            // Always add itself to the list as the first one
            UniqueSet set = new UniqueSet();
            set.Add(this);
 
            // If the form has a deactivate handler, then we
            // can't send the form with linked forms, because server interaction
            // is necessary to move between forms.
 
            if (HasDeactivateHandler())
            {
                return set;
            }
 
            // Will stop once no new forms are added in a pass, or has
            // reached the optimum page weight.
 
            int totalWeight = 0;
            int i;
 
            // negative means the caller doesn't care about the weight
            bool checkWeight = optimumPageWeight >= 0;
 
            for (i = 0; i < set.Count; i++)
            {
                Form form = (Form)set[i];
 
                if (checkWeight)
                {
                    totalWeight += form.GetVisibleWeight();
                    if (totalWeight > optimumPageWeight)
                    {
                        break;
                    }
                }
                form.AddLinkedForms(set);
            }
 
            // More forms may have been linked than the total weight allows.
            // Remove these.
 
            if (i != 0 &&  // i == 0 means only one form is in the list
                i < set.Count)
            {
                for (int j = set.Count - 1; j >= i; j--)
                {
                    set.RemoveAt(j);
                }
            }
 
            return set;
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.CreateDefaultTemplatedUI"]/*' />
        public override void CreateDefaultTemplatedUI(bool doDataBind) 
        {
            ITemplate headerTemplate = GetTemplate(Constants.HeaderTemplateTag);
            ITemplate footerTemplate = GetTemplate(Constants.FooterTemplateTag);
            ITemplate scriptTemplate = GetTemplate(Constants.ScriptTemplateTag);
 
            if (scriptTemplate != null)
            {
                _scriptContainer = new TemplateContainer();
                // The scriptTemplate is not added to the controls tree, so no need to do
                // CheckedInstantiateTemplate to check for infinite recursion.
                scriptTemplate.InstantiateIn(_scriptContainer);
                _scriptContainer.EnablePagination = false;
            }
 
            if (headerTemplate != null)
            {
                _headerContainer = new TemplateContainer();
                CheckedInstantiateTemplate (headerTemplate, _headerContainer, this);
                _headerContainer.EnablePagination = false;
                Controls.AddAt(0, _headerContainer);
            }
            
            if (footerTemplate != null)
            {
                _footerContainer = new TemplateContainer();
                CheckedInstantiateTemplate (footerTemplate, _footerContainer, this);
                _footerContainer.EnablePagination = false;
                Controls.Add(_footerContainer);
            }
 
            // Do not call base.CreateDefaultTemplatedUI(), since we don't want
            // Forms to have ContentTemplates as Panels do.
        }
 
        private int _pageCount = -1;
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.PageCount"]/*' />
        [
            Bindable(false),
            Browsable(false),
            DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public int PageCount
        {
            get
            {
                // If not yet paginated, it's okay to return -1.
 
                return _pageCount;
            }
        }
 
        private int _currentPage = 1;
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.CurrentPage"]/*' />
        [
            Bindable(false),
            Browsable(false),
            DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public int CurrentPage
        {
            get
            {
                return _currentPage;
            }
            set
            {
                if (_currentPage != value) 
                {
                    OnPageChange (_currentPage, value);
                }
                _currentPage = value;
                _cachedCurrentPage = _currentPage;
            }
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.BreakAfter"]/*' />
        [
            Bindable(false),
            Browsable(false),
            DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
            EditorBrowsable(EditorBrowsableState.Never)
        ]
        public override bool BreakAfter
        {
            get
            {
                if (MobilePage.DesignMode)
                {
                    return true;
                }
                throw new Exception(
                    SR.GetString(SR.Form_PropertyNotAccessible, "BreakAfter"));
            }
 
            set
            {
                throw new Exception(
                    SR.GetString(SR.Form_PropertyNotSettable, "BreakAfter"));
            }
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.OnPreRender"]/*' />
        protected override void OnPreRender(EventArgs e)
        {
            // AUI 3630
            base.OnPreRender(e);
 
            _pageCount = PaginateForm();
 
            // Clamp to 1 < _currentPage <= PageCount
 
            int page = Math.Max(Math.Min(_currentPage, _pageCount), 1);
            if(_currentPage != page)
            {
                _currentPage = page;
            }
 
            if ((Paginate) || (ControlToPaginate != null))
            {
                OnPaginated(new EventArgs());
            }
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Render"]/*' />
        protected override void Render(HtmlTextWriter writer)
        {
            MobilePage.EnterFormRender(this);
            OnRender(writer);
            MobilePage.ExitFormRender();
        }
 
        private int PaginateForm()
        {
            int pageWeight = MobilePage.Adapter.OptimumPageWeight;
            if (Header != null)
            {
                pageWeight -= Header.VisibleWeight;
            }
            if (Footer != null)
            {
                pageWeight -= Footer.VisibleWeight;
            }
            if (pageWeight <= 0)
            {
                //
 
 
                pageWeight = MobilePage.Adapter.OptimumPageWeight / 2;
            }
 
            if (IsFormPaginationAllowed())
            {
                if ((Paginate) || (ControlToPaginate == this))
                {
                    ControlPager pager = new ControlPager(this, pageWeight);
                    base.PaginateRecursive(pager);
                    return pager.PageCount;
                }
                else if(ControlToPaginate != null)
                {
                    ControlPager pager = new ControlPager(this, pageWeight);
                    SetControlPage(1);
                    Control control = ControlToPaginate;
                    MobileControl ctp = control as MobileControl;
                    if(ctp != null) 
                    {
                        ctp.PaginateRecursive(pager);
                    }
                    else 
                    {
                        int firstAssignedPage = -1;
                        DoPaginateChildren(pager, control, ref firstAssignedPage);
                    }
                    while(control != this)
                    {
                        MobileControl mc = control as MobileControl;
                        if(mc != null)
                        {
                            if(mc is Form)
                            {
                                throw(new Exception(SR.GetString(SR.Form_InvalidControlToPaginateForm)));
                            }
                            if (mc.FirstPage > ctp.FirstPage)
                            {
                                mc.FirstPage = ctp.FirstPage;
                            }
                            if(mc.LastPage < ctp.LastPage)
                            {
                                mc.LastPage = ctp.LastPage;
                            }
                        }
                        control = control.Parent;
                    }
                    this.LastPage = Math.Max(pager.PageCount, 1);
                    if(Header != null)
                    {
                        SetEnablePaginationRecursive(Header, false);
                    }
                    if(Footer != null)
                    {
                        SetEnablePaginationRecursive(Footer, false);
                    }
                    return this.LastPage;
                }
            }
            
            return 1;
        }
 
        private bool IsFormPaginationAllowed()
        {
            // AUI 4721
 
            if (Action.Length == 0)
            {
                return true;
            }
 
            MobileCapabilities device = (MobileCapabilities)Page.Request.Browser;
            String type = device.PreferredRenderingType;
            bool javascriptSupported = device.JavaScript;
 
            return javascriptSupported || 
                    (type != MobileCapabilities.PreferredRenderingTypeHtml32 &&
                     type != MobileCapabilities.PreferredRenderingTypeChtml10);
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.PaginateRecursive"]/*' />
        public override void PaginateRecursive(ControlPager pager)
        {
            _pageCount = PaginateForm();
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.PaginateChildren"]/*' />
        protected override bool PaginateChildren
        {
            get
            {
                return true;
            }
        }
 
        private Control _controlToPaginate = null;
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.ControlToPaginate"]/*' />
        [
            Bindable(false),
            Browsable(false),
            DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public Control ControlToPaginate
        {
            get
            {
                if(_controlToPaginate != null)
                {
                    return _controlToPaginate;
                }
                if(ViewState["ControlToPaginate"] != null)
                {
                    _controlToPaginate = Page.FindControl((ViewState["ControlToPaginate"]).ToString());
                }
                return _controlToPaginate;
            }
            set
            {
                if(value != null)
                {
                    ViewState["ControlToPaginate"] = value.UniqueID;
                }
                else
                {
                    ViewState.Remove("ControlToPaginate");
                }
                _controlToPaginate = value;
            }
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.LoadPrivateViewState"]/*' />
        protected override void LoadPrivateViewState(Object state)
        {
            _currentPage = state != null ? (int)state : 1;
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.SavePrivateViewState"]/*' />
        protected override Object SavePrivateViewState()
        {
            int currentPage = _currentPage;
            if (currentPage > 1 && this == MobilePage.ActiveForm)
            {
                return currentPage;
            }
            else
            {
                return null;
            }
        }
 
        /// <include file='doc\Form.uex' path='docs/doc[@for="Form.OnDataBinding"]/*' />
        protected override void OnDataBinding(EventArgs e)
        {
            if(Script != null)
            {
                Script.DataBind();
            }
            base.OnDataBinding(e);
        }
 
        private IPostBackEventHandler _defaultEventHandler = null;
        internal void RegisterEventHandler(IPostBackEventHandler control)
        {
            if (_defaultEventHandler == null)
            {
                _defaultEventHandler = control;
            }
        }
 
        internal IPostBackEventHandler DefaultEventHandler
        {
            get
            {
                return _defaultEventHandler;
            }
        }
 
        internal override void InvalidateParentStyles()
        {
            PagerStyle.InvalidateParentStyle();
            base.InvalidateParentStyles();
        }
 
        #region IPostBackEventHandler implementation
        void IPostBackEventHandler.RaisePostBackEvent(String eventArgument) {
            RaisePostBackEvent(eventArgument);
        }
        #endregion 
    }
 
    /// <include file='doc\Form.uex' path='docs/doc[@for="FormControlBuilder"]/*' />
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)]
    [Obsolete("The System.Web.Mobile.dll assembly has been deprecated and should no longer be used. For information about how to develop ASP.NET mobile applications, see http://go.microsoft.com/fwlink/?LinkId=157231.")]
    public class FormControlBuilder : LiteralTextContainerControlBuilder
    {
        /// <include file='doc\Form.uex' path='docs/doc[@for="FormControlBuilder.AppendSubBuilder"]/*' />
        public override void AppendSubBuilder(ControlBuilder subBuilder)
        {
            Type controlType = subBuilder.ControlType;
            if(!(
                 (subBuilder.GetType().FullName == "System.Web.UI.CodeBlockBuilder") ||
                 (typeof(MobileControl).IsAssignableFrom(controlType)) ||
                 (typeof(UserControl).IsAssignableFrom(controlType)) ||
                 (typeof(DeviceSpecific).IsAssignableFrom(controlType))
                 ))
            {
                throw(new Exception(SR.GetString(SR.Form_InvalidSubControlType, subBuilder.TagName)));
            }
            base.AppendSubBuilder(subBuilder);
        }
    }
}