File: UI\MobileControls\Adapters\HtmlSelectionListAdapter.cs
Project: ndp\fx\src\mit\System\Web\System.Web.Mobile.csproj (System.Web.Mobile)
//------------------------------------------------------------------------------
// <copyright file="HtmlSelectionListAdapter.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
using System;
using System.Globalization;
using System.IO;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.MobileControls;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Security.Permissions;
 
#if COMPILING_FOR_SHIPPED_SOURCE
namespace System.Web.UI.MobileControls.ShippedAdapterSource
#else
namespace System.Web.UI.MobileControls.Adapters
#endif
 
{
    /*
     * HtmlSelectionListAdapter provides the html device functionality for SelectionList controls.
     *
     * Copyright (c) 2000 Microsoft Corporation
     */
    /// <include file='doc\HtmlSelectionListAdapter.uex' path='docs/doc[@for="HtmlSelectionListAdapter"]/*' />
    [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 HtmlSelectionListAdapter : HtmlControlAdapter
    {
        /// <include file='doc\HtmlSelectionListAdapter.uex' path='docs/doc[@for="HtmlSelectionListAdapter.Control"]/*' />
        protected new SelectionList Control
        {
            get
            {
                return (SelectionList)base.Control;
            }
        }
 
        /// <include file='doc\HtmlSelectionListAdapter.uex' path='docs/doc[@for="HtmlSelectionListAdapter.OnInit"]/*' />
        public override void OnInit(EventArgs e)
        {
        }
 
        /// <include file='doc\HtmlSelectionListAdapter.uex' path='docs/doc[@for="HtmlSelectionListAdapter.Render"]/*' />
        public override void Render(HtmlMobileTextWriter writer)
        {
            MobileListItemCollection items = Control.Items;
            ListSelectType selectType = Control.SelectType;
 
            if (items.Count == 0 && 
                selectType != ListSelectType.ListBox && 
                selectType != ListSelectType.MultiSelectListBox)
            {
                return;
            }
            
            int selectedIndex = Control.SelectedIndex;
            String renderName;
            if(Device.RequiresAttributeColonSubstitution)
            {
                renderName = Control.UniqueID.Replace(':', ',');
            }
            else
            {
                renderName = Control.UniqueID;
            }
 
            switch(selectType)
            {
                case ListSelectType.DropDown:
                case ListSelectType.ListBox:
                case ListSelectType.MultiSelectListBox:
 
                    if (items.Count == 0 && !Device.CanRenderEmptySelects)
                    {
                        break;
                    }
 
                    writer.EnterLayout(Style);
                    writer.WriteBeginTag("select");
 
                    if (selectType == ListSelectType.MultiSelectListBox)
                    {
                        writer.Write(" multiple");
                    }
 
                    if (selectType == ListSelectType.ListBox || selectType == ListSelectType.MultiSelectListBox)
                    {
                        writer.WriteAttribute("size", Control.Rows.ToString(CultureInfo.InvariantCulture));
                    }
 
                    writer.WriteAttribute("name", renderName);
                    writer.Write(">");
 
                    for(int itemIndex = 0; itemIndex < items.Count; itemIndex++)
                    {
                        MobileListItem item = items[itemIndex];
                        writer.WriteBeginTag("option");
                        WriteItemValueAttribute(writer, itemIndex, item.Value);
                        if (item.Selected && (Control.IsMultiSelect || itemIndex == selectedIndex))
                        {
                            writer.Write(" selected>");
                        }
                        else
                        {
                            writer.Write(">");
                        }
                        writer.WriteEncodedText(item.Text);
                        writer.WriteLine("");
                    }
                    writer.Write("</select>");
            
                    if(Device.HidesRightAlignedMultiselectScrollbars &&
                        selectType == ListSelectType.MultiSelectListBox)
                    {
                        // nested if for perf
                        if((Alignment)Style[Style.AlignmentKey, true] == Alignment.Right)
                        {                                                
                            writer.Write("&nbsp;&nbsp;&nbsp;&nbsp;");
                        }
                    }
                    writer.WriteLine("");
                    
                    if (!Page.DesignMode)
                    {
                        writer.ExitLayout(Style, Control.BreakAfter);
                    }
                    else
                    {
                        writer.ExitLayout(Style, false);
                    }
                    break;
 
                case ListSelectType.Radio:
                case ListSelectType.CheckBox:
 
                    String selectTypeString =
                        (selectType == ListSelectType.Radio) ?
                        "radio" :
                        "checkbox";
                    Alignment alignment = (Alignment)Style[Style.AlignmentKey, true];
                    if(!Device.Tables || alignment == Alignment.Left || alignment == Alignment.NotSet)
                    {
                        writer.EnterStyle(Style);
                        bool breakAfter = false;
                        for(int itemIndex = 0; itemIndex < items.Count; itemIndex++)
                        {
                            if(breakAfter)
                            {
                                writer.WriteBreak();
                            }
                            MobileListItem item = items[itemIndex];
 
                            writer.WriteBeginTag("input");
                            writer.WriteAttribute("type", selectTypeString);
                            writer.WriteAttribute("name", renderName);
                            WriteItemValueAttribute(writer, itemIndex, item.Value);
                            if (item.Selected && 
                                (Control.IsMultiSelect || itemIndex == selectedIndex) &&
                                Device.SupportsUncheck)
                            {
                                writer.Write(" checked>");
                            }
                            else
                            {
                                writer.Write(">");
                            }
                            writer.WriteEncodedText(item.Text);
                            breakAfter = true;
                        }
                        writer.ExitStyle(Style, Control.BreakAfter);
                    }
                    else // Device supports tables and alignment is non default.
                    {
                        Wrapping  wrapping  = (Wrapping) Style[Style.WrappingKey , true];
                        bool nowrap = (wrapping == Wrapping.NoWrap);
 
                        writer.EnterLayout(Style);
                        writer.WriteFullBeginTag("table");
                        writer.BeginStyleContext();
                        for(int itemIndex = 0; itemIndex < items.Count; itemIndex++)
                        {
                            MobileListItem item = items[itemIndex];
                            writer.WriteFullBeginTag("tr");
                            writer.WriteBeginTag("td");
                            if(nowrap)
                            {
                                writer.WriteAttribute("nowrap","true");
                            }
                            writer.Write(">");
 
                            writer.WriteBeginTag("input");
                            writer.WriteAttribute("type", selectTypeString);
                            writer.WriteAttribute("name", renderName);
                            WriteItemValueAttribute(writer, itemIndex, item.Value);
                            if (item.Selected && 
                                (Control.IsMultiSelect || itemIndex == selectedIndex) &&
                                Device.SupportsUncheck)
                            {
                                writer.Write(" checked>");
                            }
                            else
                            {
                                writer.Write(">");
                            }
 
                            writer.MarkStyleContext();
                            writer.EnterFormat(Style);
                            writer.WriteEncodedText(item.Text);
                            writer.ExitFormat(Style);
                            writer.UnMarkStyleContext();
                            writer.WriteEndTag("td");
                            writer.WriteEndTag("tr");
                        }
                        writer.WriteEndTag("table");
                        writer.EndStyleContext();
                        writer.ExitFormat(Style, Control.BreakAfter);
                    }
                break;
            }
        }
 
        // Parse the HTML posted data appropriately.
        /// <include file='doc\HtmlSelectionListAdapter.uex' path='docs/doc[@for="HtmlSelectionListAdapter.LoadPostData"]/*' />
        public override bool LoadPostData(String key,
                                          NameValueCollection data,
                                          Object controlPrivateData,
                                          out bool dataChanged)
        {
            String[] selectedItems = data.GetValues(key);
            Debug.Assert (String.IsNullOrEmpty(Control.Form.Action), 
                "Cross page post (!IsPostBack) assumed when Form.Action nonempty." +
                "LoadPostData should not have been be called.");
 
            // If no post data is included, and the control is either not visible, or
            // not on active form, this call should be ignored (the lack of post data 
            // is not due to there being no selection, but due to there being no 
            // markup rendered that could generate the post data).
 
            if (selectedItems == null && 
                    (!Control.Visible || Control.Form != Control.MobilePage.ActiveForm))
            {
                dataChanged = false;
                return true;
            }
 
            // Case where nothing is selected.
            if(selectedItems == null ||
               (selectedItems.Length == 1 && (selectedItems[0] != null && selectedItems[0].Length == 0)))
            {
                selectedItems = new String[]{};
            }
 
            int[] selectedItemIndices = new int[selectedItems.Length];
 
            // Note: controlPrivateData is selected indices from the viewstate.
            int[] originalSelectedIndices = (int[])controlPrivateData;
            dataChanged = false;
 
            // If SelectType is DropDown && nothing was selected, select
            // first elt.  (Non-mobile DropDown does same by getting SelectedIndex).
            if(Control.SelectType == ListSelectType.DropDown &&
               originalSelectedIndices.Length == 0 &&
               Control.Items.Count > 0)
            {
                Control.Items[0].Selected = true;
                originalSelectedIndices = new int[]{0};
            }
 
            for(int i = 0; i < selectedItems.Length; i++)
            {
                selectedItemIndices[i] = Int32.Parse(selectedItems[i], CultureInfo.InvariantCulture);
            }
 
            // Do not assume posted selected indices are ascending.
            // We do know originalSelectedIndices are ascending.
            Array.Sort(selectedItemIndices);
 
            // Check whether selections have changed.
            if(selectedItemIndices.Length != originalSelectedIndices.Length)
            {
                dataChanged = true;
            }
            else
            {
                for(int i = 0; i < selectedItems.Length; i++)
                {
                    if(selectedItemIndices[i] != originalSelectedIndices[i])
                    {
                        dataChanged = true;
                    }
                }
            }
 
            for (int i = 0; i < Control.Items.Count; i++)
            {
                Control.Items[i].Selected = false;
            }
 
            for(int i = 0; i < selectedItemIndices.Length; i++)
            {
                Control.Items[selectedItemIndices[i]].Selected = true;
            }
            return true;
        }
 
        private void WriteItemValueAttribute(HtmlTextWriter writer, int index, String value)
        {
            if (Page.DesignMode || String.IsNullOrEmpty(Control.Form.Action))
            {
                writer.WriteAttribute("value", index.ToString(CultureInfo.InvariantCulture));
            }
            else
            {
                writer.WriteAttribute("value", value, true /*encode*/);
            }
        }
 
        /// <include file='doc\HtmlSelectionListAdapter.uex' path='docs/doc[@for="HtmlSelectionListAdapter.RenderAsHiddenInputField"]/*' />
        protected override void RenderAsHiddenInputField(HtmlMobileTextWriter writer)
        {
            // Optimization - if viewstate is enabled for this control, and the
            // postback returns to this page, we just let it do the trick.
            // One catch though - if the control is multiselect, it always 
            // interprets return values, so we do need to write out.
 
            if (Control.IsMultiSelect || Control.Form.Action.Length > 0 || !IsViewStateEnabled())
            {
                String uniqueID = Control.UniqueID;
                MobileListItemCollection items = Control.Items;
                for (int i = 0; i < items.Count; i++)
                {
                    if (items[i].Selected)
                    {
                        writer.WriteHiddenField(uniqueID, i.ToString(CultureInfo.InvariantCulture));
                    }
                }
            }
        }
 
        private bool IsViewStateEnabled()
        {
            Control ctl = Control;
            while (ctl != null)
            {
                if (!ctl.EnableViewState)
                {
                    return false;
                }
                ctl = ctl.Parent;
            }
            return true;
        }
   }
}