File: UI\MobileControls\Adapters\WmlObjectListAdapter.cs
Project: ndp\fx\src\mit\System\Web\System.Web.Mobile.csproj (System.Web.Mobile)
//------------------------------------------------------------------------------
// <copyright file="WmlObjectListAdapter.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Web;
using System.Web.UI;
using System.Web.UI.MobileControls;
using System.Web.UI.MobileControls.Adapters;
using System.Security.Permissions;
 
#if COMPILING_FOR_SHIPPED_SOURCE
namespace System.Web.UI.MobileControls.ShippedAdapterSource
#else
namespace System.Web.UI.MobileControls.Adapters
#endif    
 
{
 
    /*
     * WmlObjectListAdapter provides WML rendering of Object List control.
     *
     * Copyright (c) 2000 Microsoft Corporation
     */
    /// <include file='doc\WmlObjectListAdapter.uex' path='docs/doc[@for="WmlObjectListAdapter"]/*' />
    [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 WmlObjectListAdapter : WmlControlAdapter
    {
        private const String _backToList = "__back";
        private const String _showMenu = "__menu";
        private const String _showDetails = "__details";
        private const String _showMoreFormat = "__more$({0})";
        private const String _showMoreFormatAnchor = "__more{0}";
        private const String _showMore = "__more";
        private const int _modeItemMenu = 1;
        private const int _modeItemDetails = 2;
 
        /// <include file='doc\WmlObjectListAdapter.uex' path='docs/doc[@for="WmlObjectListAdapter.Control"]/*' />
        protected new ObjectList Control
        {
            get
            {
                return (ObjectList)base.Control;
            }
        }
 
        /// <include file='doc\WmlObjectListAdapter.uex' path='docs/doc[@for="WmlObjectListAdapter.OnPreRender"]/*' />
        public override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            switch (Control.ViewMode)
            {
                case ObjectListViewMode.List:
                    SecondaryUIMode = NotSecondaryUI;
                    break;
 
                case ObjectListViewMode.Commands:
                    SecondaryUIMode = _modeItemMenu;
                    break;
 
                case ObjectListViewMode.Details:
                    SecondaryUIMode = _modeItemDetails;
                    break;
            }
 
            if(Control.MobilePage.ActiveForm == Control.Form && 
                Control.Visible && 
                Control.ViewMode == ObjectListViewMode.Commands &&
                Control.Items.Count > 0)
            {
                Control.PreShowItemCommands (Control.SelectedIndex);
            }
        }
 
        /// <include file='doc\WmlObjectListAdapter.uex' path='docs/doc[@for="WmlObjectListAdapter.Render"]/*' />
        public override void Render(WmlMobileTextWriter writer)
        {
            switch (Control.ViewMode)
            {
                case ObjectListViewMode.List:
                    if (Control.HasControls())
                    {
                        writer.BeginCustomMarkup();
                        RenderChildren(writer);
                        writer.EndCustomMarkup();
                        return;
                    }
                    RenderItemsList(writer);
                    break;
 
                case ObjectListViewMode.Commands:
                    RenderItemMenu(writer, Control.Selection);
                    break;
 
                case ObjectListViewMode.Details:
                    if (Control.Selection.HasControls())
                    {
                        writer.BeginCustomMarkup();
                        Control.Selection.RenderChildren(writer);
                        writer.EndCustomMarkup();
                        return;
                    }
                    RenderItemDetails(writer, Control.Selection);
                    break;
            }
        }
 
        /// <include file='doc\WmlObjectListAdapter.uex' path='docs/doc[@for="WmlObjectListAdapter.CreateTemplatedUI"]/*' />
        public override void CreateTemplatedUI(bool doDataBind)
        {
            if (Control.ViewMode == ObjectListViewMode.List)
            {
                Control.CreateTemplatedItemsList(doDataBind);
            }
            else
            {
                Control.CreateTemplatedItemDetails(doDataBind);
            }
        }
 
        /// <include file='doc\WmlObjectListAdapter.uex' path='docs/doc[@for="WmlObjectListAdapter.RenderItemsList"]/*' />
        protected virtual void RenderItemsList(WmlMobileTextWriter writer)
        {
            bool rendersAcceptsInline = Device.RendersWmlDoAcceptsInline;
            bool rendersSelectsAsMenuCards = Device.RendersWmlSelectsAsMenuCards;
            bool rendersBreaksAfterAnchor = Device.RendersBreaksAfterWmlAnchor;
            int pageStart = Control.FirstVisibleItemIndex;
            int pageSize = Control.VisibleItemCount;
            ObjectListItemCollection items = Control.Items;
 
            if (pageSize == 0 || items.Count == 0)
            {
                return;
            }
 
            bool hasDefaultCommand = HasDefaultCommand();
            bool onlyHasDefaultCommand = OnlyHasDefaultCommand();
            bool requiresSecondScreen = HasItemDetails() || (!onlyHasDefaultCommand && HasCommands());
            bool itemRequiresHyperlink = requiresSecondScreen || hasDefaultCommand;
 
            writer.EnterLayout(Style);
 
            int[] tableFieldIndices = null;
            if (ShouldRenderAsTable() && (tableFieldIndices = Control.TableFieldIndices).Length != 0)
            {
                writer.BeginCustomMarkup();
                int fieldCount = tableFieldIndices.Length;
                writer.Write("<table columns=\"");
                writer.Write(fieldCount.ToString(CultureInfo.InvariantCulture));
                writer.WriteLine("\">");
 
                if (ShouldRenderTableHeaders())
                {
                    writer.Write("<tr>");
                    foreach (int fieldIndex in tableFieldIndices)
                    {
                        writer.Write("<td>");
                        writer.RenderText(Control.AllFields[fieldIndex].Title);
                        writer.Write("</td>");
                    }
                    writer.WriteLine("</tr>");
                }
 
                for (int i = 0; i < pageSize; i++)
                {
                    ObjectListItem item = items[pageStart + i];
                    writer.Write("<tr>");
                    for (int field = 0; field < fieldCount; field++)
                    {
                        writer.Write("<td>");
                        if (field == 0 && itemRequiresHyperlink)
                        {
                            RenderPostBackEvent(writer, 
                                requiresSecondScreen ?
                                    String.Format(CultureInfo.InvariantCulture, _showMoreFormatAnchor, item.Index) :
                                    item.Index.ToString(CultureInfo.InvariantCulture),
                                GetDefaultLabel(GoLabel),
                                false,
                                item[tableFieldIndices[0]],
                                false,
                                WmlPostFieldType.Raw);
                        }
                        else
                        {
                            writer.RenderText(item[tableFieldIndices[field]]);
                        }
                        writer.Write("</td>");
                    }
                    writer.WriteLine("</tr>");
                }
                writer.WriteLine("</table>");
                writer.EndCustomMarkup();
            }
            else
            {
                int labelFieldIndex = Control.LabelFieldIndex;
                ObjectListField labelField = Control.AllFields[labelFieldIndex];
 
                writer.EnterFormat(Style);
                for (int i = 0; i < pageSize; i++)
                {
                    ObjectListItem item = items[pageStart + i];
                    if (itemRequiresHyperlink)
                    {
                        RenderPostBackEvent(writer, 
                            requiresSecondScreen ?
                                String.Format(CultureInfo.InvariantCulture, _showMoreFormatAnchor, item.Index) :
                                item.Index.ToString(CultureInfo.InvariantCulture),
                            GetDefaultLabel(GoLabel),
                            false,
                            item[labelFieldIndex],
                            true,
                            WmlPostFieldType.Raw);
                    }
                    else
                    {
                        writer.RenderText(item[labelFieldIndex], true);
                    }
                }
                writer.ExitFormat(Style);
            }
 
            writer.ExitLayout(Style);
        }
 
        /// <include file='doc\WmlObjectListAdapter.uex' path='docs/doc[@for="WmlObjectListAdapter.RenderItemMenu"]/*' />
        protected virtual void RenderItemMenu(WmlMobileTextWriter writer, ObjectListItem item)
        {
            bool requiresDetails = HasItemDetails();
 
            String detailsCommandText = Control.DetailsCommandText.Length == 0 ?
                SR.GetString(SR.WmlObjectListAdapterDetails) :
                Control.DetailsCommandText;
            String softkeyLabel = detailsCommandText.Length <= Device.MaximumSoftkeyLabelLength ?
                detailsCommandText :
                null;
            Style commandStyle = Control.CommandStyle;
            if (commandStyle.Alignment == Alignment.NotSet)
            {
                commandStyle.Alignment = Alignment.Left;
            }
            writer.EnterStyle(commandStyle);
            if (requiresDetails)
            {
                RenderPostBackEvent(writer, _showDetails,
                        softkeyLabel, true, detailsCommandText, true, WmlPostFieldType.Raw);
            }
 
            ObjectListCommandCollection commands = Control.Commands;
            foreach (ObjectListCommand command in commands)
            {
                RenderPostBackEvent(writer, command.Name, 
                    GetDefaultLabel(GoLabel), false, command.Text, true, WmlPostFieldType.Raw);
            }
            writer.ExitStyle(commandStyle);
        }
 
        /// <include file='doc\WmlObjectListAdapter.uex' path='docs/doc[@for="WmlObjectListAdapter.RenderItemDetails"]/*' />
        protected virtual void RenderItemDetails(WmlMobileTextWriter writer, ObjectListItem item)
        {
            String backCommandText = Control.BackCommandText.Length == 0 ?
                GetDefaultLabel(BackLabel) :
                Control.BackCommandText;
            String softkeyLabel = backCommandText.Length <= Device.MaximumSoftkeyLabelLength ?
                backCommandText :
                null;
 
            Style labelStyle = Control.LabelStyle;
            writer.EnterStyle(labelStyle);
            writer.RenderText(item[Control.LabelFieldIndex], true);
            writer.ExitStyle(labelStyle);
 
            writer.EnterStyle(Style);
            IObjectListFieldCollection fields = Control.AllFields;
            int fieldIndex = 0;
            foreach (ObjectListField field in fields)
            {
                if (field.Visible)
                {
                    String displayText = String.Format(CultureInfo.InvariantCulture, "{0}: {1}", field.Title, item[fieldIndex]);
                    writer.RenderText(displayText, true);
                }
                fieldIndex++;
            }
            RenderPostBackEvent(writer, _backToList, softkeyLabel, true, backCommandText, true);
            writer.ExitStyle(Style);
        }
 
        /// <include file='doc\WmlObjectListAdapter.uex' path='docs/doc[@for="WmlObjectListAdapter.HandlePostBackEvent"]/*' />
        public override bool HandlePostBackEvent(String eventArgument)
        {
            switch (Control.ViewMode)
            {
                case ObjectListViewMode.List:
 
                    // DCR 2493 - raise a selection event, and only continue
                    // handling if asked to.
 
                    if (eventArgument.StartsWith(_showMore, StringComparison.Ordinal))
                    {
                        int itemIndex = ParseItemArg(eventArgument);
 
                        if (Control.SelectListItem(itemIndex, true))
                        {
                            if (HasCommands())
                            {
                                Control.ViewMode = ObjectListViewMode.Commands;
                            }
                            else
                            {
                                Control.ViewMode = ObjectListViewMode.Details;
                            }
                        }
                    }
                    else
                    {
                        int itemIndex = -1;
                        try
                        {
                            itemIndex = Int32.Parse(eventArgument, CultureInfo.InvariantCulture);
                        }
                        catch (System.FormatException)
                        {
                            throw new Exception (SR.GetString(SR.ObjectListAdapter_InvalidPostedData));
                        }
                        if (Control.SelectListItem(itemIndex, false))
                        {
                            Control.RaiseDefaultItemEvent(itemIndex);
                        }
                    }
                    return true;
 
                case ObjectListViewMode.Commands:
 
                    if (eventArgument == _backToList)
                    {
                        Control.ViewMode = ObjectListViewMode.List;
                        return true;
                    }
                    else if (eventArgument == _showDetails)
                    {
                        Control.ViewMode = ObjectListViewMode.Details;
                        return true;
                    }
                    break;
 
                case ObjectListViewMode.Details:
 
                    if (eventArgument == _backToList)
                    {
                        Control.ViewMode = ObjectListViewMode.List;
                        return true;
                    }
                    else if (eventArgument == _showMenu)
                    {
                        Control.ViewMode = ObjectListViewMode.Commands;
                        return true;
                    }
                    break;
            }
 
            return false;
        }
 
        private static int ParseItemArg(String arg)
        {
            return Int32.Parse(arg.Substring(_showMore.Length), CultureInfo.InvariantCulture);
        }
 
        /// <include file='doc\WmlObjectListAdapter.uex' path='docs/doc[@for="WmlObjectListAdapter.ShouldRenderAsTable"]/*' />
        protected virtual bool ShouldRenderAsTable()
        {
            int avgFieldWidth = 10; // an arbitrary estimate.
            return Device.ScreenCharactersHeight > 4 && VisibleTableFieldsCount * avgFieldWidth < Device.ScreenCharactersWidth;
        }
 
        private bool ShouldRenderTableHeaders()
        {
            return true;
        }
 
        private BooleanOption _hasItemDetails = BooleanOption.NotSet;
        /// <include file='doc\WmlObjectListAdapter.uex' path='docs/doc[@for="WmlObjectListAdapter.HasItemDetails"]/*' />
        protected bool HasItemDetails()
        {
            if(Control.Items.Count == 0)
            {
                return false;
            }
            if (_hasItemDetails == BooleanOption.NotSet)
            {
                // Calculate how many visible fields are shown in list view.
 
                int visibleFieldsInListView;
                int[] tableFieldIndices;
                if (ShouldRenderAsTable() && (tableFieldIndices = Control.TableFieldIndices).Length != 0)
                {
                    visibleFieldsInListView = 0;
                    for (int i = 0; i < tableFieldIndices.Length; i++)
                    {
                        if (Control.AllFields[tableFieldIndices[i]].Visible)
                        {
                            visibleFieldsInListView++;
                        }
                    }
                }
                else
                {
                    visibleFieldsInListView = Control.AllFields[Control.LabelFieldIndex].Visible ?
                                                    1 : 0;
                }
 
 
                // Calculate the number of visible fields.
 
                _hasItemDetails = BooleanOption.False;
                int visibleFieldCount = 0;
                foreach (ObjectListField field in Control.AllFields)
                {
                    if (field.Visible)
                    {
                        visibleFieldCount++;
                        if (visibleFieldCount > visibleFieldsInListView)
                        {
                            _hasItemDetails = BooleanOption.True;
                            break;
                        }
                    }
                }
            }
 
            return _hasItemDetails == BooleanOption.True;
        }
 
        /// <include file='doc\WmlObjectListAdapter.uex' path='docs/doc[@for="WmlObjectListAdapter.HasCommands"]/*' />
        protected bool HasCommands()
        {
            return Control.Commands.Count > 0;
        }
 
        /// <include file='doc\WmlObjectListAdapter.uex' path='docs/doc[@for="WmlObjectListAdapter.HasDefaultCommand"]/*' />
        protected bool HasDefaultCommand()
        {
            return Control.DefaultCommand.Length > 0;
        }
 
        private BooleanOption _onlyHasDefaultCommand = BooleanOption.NotSet;
        /// <include file='doc\WmlObjectListAdapter.uex' path='docs/doc[@for="WmlObjectListAdapter.OnlyHasDefaultCommand"]/*' />
        protected bool OnlyHasDefaultCommand()
        {
            if (_onlyHasDefaultCommand == BooleanOption.NotSet)
            {
                String defaultCommand = Control.DefaultCommand;
                if (defaultCommand.Length > 0)
                {
                    int commandCount = Control.Commands.Count;
                    if (commandCount == 0 || 
                        (commandCount == 1 && 
                            String.Compare(defaultCommand, Control.Commands[0].Name, StringComparison.OrdinalIgnoreCase) == 0))
                    {
                        _onlyHasDefaultCommand = BooleanOption.True;
                    }
                    else
                    {
                        _onlyHasDefaultCommand = BooleanOption.False;
                    }
                }
                else
                {
                    _onlyHasDefaultCommand = BooleanOption.False;
                }
            }
 
            return _onlyHasDefaultCommand == BooleanOption.True;
        }
        
        // This appears in both Html and Wml adapters, is used in
        // ShouldRenderAsTable().  In adapters rather than control
        // because specialized rendering method.
        private int _visibleTableFieldsCount = -1;
        private int VisibleTableFieldsCount
        {
            get
            {
                if (_visibleTableFieldsCount == -1)
                {
                    int[] tableFieldIndices = Control.TableFieldIndices;
                    _visibleTableFieldsCount = 0;
                    for (int i = 0; i < tableFieldIndices.Length; i++)
                    {
                        if (Control.AllFields[tableFieldIndices[i]].Visible)
                        {
                            _visibleTableFieldsCount++;
                        }
                    }
                }
                return _visibleTableFieldsCount;
            }
        }
 
 
    }
}