File: DynamicData\FilterRepeater.cs
Project: ndp\fx\src\xsp\system\DynamicData\System.Web.DynamicData.csproj (System.Web.DynamicData)
namespace System.Web.DynamicData {
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Linq;
    using System.Security.Permissions;
    using System.Web;
    using System.Web.Compilation;
    using System.Web.Resources;
    using System.Web.UI;
    using System.Web.UI.WebControls;
 
    /// <summary>
    /// Repeater Control that enumerates over all the filterable columns in a table
    /// </summary>
    [ToolboxItem(false)]
    [ParseChildren(true)]
    public class FilterRepeater : Repeater, IWhereParametersProvider {
        private string _contextTypeName;
        private string _dynamicFilterContainerId;
        private List<FilterUserControlBase> _filters = new List<FilterUserControlBase>();
        private MetaTable _table;
        private string _tableName;
 
        /// <summary>
        /// The context that the filtered table belongs to
        /// </summary>
        [Category("Data"),
        DefaultValue((string)null),
        Themeable(false)]
        // 
        public string ContextTypeName {
            get {
                return _contextTypeName ?? String.Empty;
            }
            set {
                if (!ContextTypeName.Equals(value)) {
                    _contextTypeName = value;
                    _table = null;
                }
            }
        }
 
        /// <summary>
        /// ID of the filter control in the ItemTemplate. By default, it's "DynamicFilter".
        /// </summary>
        [Category("Behavior"),
        DefaultValue("DynamicFilter"),
        Themeable(false),
        IDReferenceProperty(typeof(FilterUserControlBase)),
        ResourceDescription("DynamicFilterRepeater_DynamicFilterContainerId")]
        public string DynamicFilterContainerId {
            get {
                if (String.IsNullOrEmpty(_dynamicFilterContainerId)) {
                    _dynamicFilterContainerId = "DynamicFilter";
                }
                return _dynamicFilterContainerId;
            }
            set {
                _dynamicFilterContainerId = value;
            }
        }
 
        /// <summary>
        /// Returns the table associated with this filter repeater.
        /// </summary>
        public MetaTable Table {
            get {
                if (_table == null) {
                    _table = GetTable();
                }
                return _table;
            }
        }
 
        /// <summary>
        /// Name of the table being filtered
        /// </summary>
        [Category("Data"),
        DefaultValue((string)null),
        Themeable(false),
        ResourceDescription("FilterRepeater_TableName")]
        public string TableName {
            get {
                return _tableName ?? String.Empty;
            }
            set {
                if (!TableName.Equals(value)) {
                    _tableName = value;
                    _table = null;
                }
            }
        }
 
        public override bool Visible {
            get {
                // 
 
 
                return base.Visible && _filters.Count > 0;
            }
            set {
                base.Visible = value;
            }
        }
 
        /// <summary>
        /// same as base.
        /// </summary>
        public override void DataBind() {
            // Start with an empty filters list when DataBinding. This is needed when DataBind()
            // gets called multiple times.
            _filters.Clear();
 
            base.DataBind();
        }
 
        /// <summary>
        /// Returns an enumeration of the columns belonging to the table associated with
        /// this filter repeater that are sortable (by default, foreign key and boolean columns)
        /// that are scaffoldable
        /// </summary>
        /// <returns></returns>
        protected internal virtual IEnumerable<MetaColumn> GetFilteredColumns() {
            return Table.Columns.Where(c => IsFilterableColumn(c));
        }
 
        internal IEnumerable<FilterUserControlBase> GetFilterControls() {
            return _filters;
        }
 
        private MetaTable GetTable() {
            if (!String.IsNullOrEmpty(ContextTypeName) || !String.IsNullOrEmpty(TableName)) {
                // get table from control properties
 
                string contextTypeName = ContextTypeName;
                string tableName = TableName;
 
                if (String.IsNullOrEmpty(ContextTypeName)) {
                    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
                        DynamicDataResources.FilterRepeater_MissingContextTypeName,
                        ID));
                } else if (String.IsNullOrEmpty(tableName)) {
                    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
                        DynamicDataResources.FilterRepeater_MissingTableName,
                        ID));
                }
 
                Type contextType = null;
                if (!String.IsNullOrEmpty(ContextTypeName)) {
                    try {
                        contextType = BuildManager.GetType(contextTypeName, /*throwOnError*/ true, /*ignoreCase*/ true);
                    } catch (Exception e) {
                        throw new InvalidOperationException(String.Format(
                            CultureInfo.CurrentCulture,
                            DynamicDataResources.FilterRepeater_InvalidContextTypeName,
                            ID,
                            contextTypeName), e);
                    }
                }
                MetaModel model;
                try {
                     model = MetaModel.GetModel(contextType);
                } catch (InvalidOperationException e) {
                    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
                        DynamicDataResources.FilterRepeater_UnknownContextTypeName,
                        ID,
                        contextType.FullName), e);
                }
                try {
                    return model.GetTable(tableName);
                } catch (ArgumentException e) {
                    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
                        DynamicDataResources.FilterRepeater_InvalidTableName,
                        ID,
                        tableName), e);
                }
            } else {
                MetaTable table = DynamicDataRouteHandler.GetRequestMetaTable(HttpContext.Current);
                if (table == null) {
                    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
                        DynamicDataResources.FilterRepeater_CantInferInformationFromUrl,
                        ID));
                }
                return table;
            }
        }
 
        internal static bool IsFilterableColumn(MetaColumn column) {
            if (!column.Scaffold) return false;
 
            if (column.IsCustomProperty) return false;
 
            if (column is MetaForeignKeyColumn) return true;
 
            if (column.ColumnType == typeof(bool)) return true;
 
            return false;
        }
 
 
        /// <summary>
        /// gets called for every item and alternating item template being instantiated by this
        /// repeater during databinding
        /// </summary>
        /// <param name="item"></param>
        protected virtual void OnFilterItemCreated(RepeaterItem item) {
            var filter = item.FindControl(DynamicFilterContainerId) as FilterUserControlBase;
            if (filter == null) {
                throw new InvalidOperationException(
                    String.Format(CultureInfo.CurrentCulture,
                        DynamicDataResources.FilterRepeater_CouldNotFindControlInTemplate,
                        ID,
                        typeof(FilterUserControlBase).FullName,
                        DynamicFilterContainerId));
            }
 
            var column = (MetaColumn)item.DataItem;
            filter.TableName = column.Table.Name;
            filter.DataField = column.Name;
            filter.ContextTypeName = column.Table.DataContextType.AssemblyQualifiedName;
 
            // Keep track of all the filters we create
            _filters.Add(filter);
        }
 
        /// <summary>
        /// See base class documentation
        /// </summary>
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        protected override void OnInit(EventArgs e) {
            base.OnInit(e);
 
            // Don't do anything in Design mode
            if (DesignMode) {
                return;
            }
 
            Page.InitComplete += new EventHandler(Page_InitComplete);
        }
 
        /// <summary>
        /// See base class documentation
        /// </summary>
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        protected override void OnItemCreated(RepeaterItemEventArgs e) {
            base.OnItemCreated(e);
 
            if (DesignMode) {
                return;
            }
 
            ListItemType listItemType = e.Item.ItemType;
            if (listItemType == ListItemType.Item || listItemType == ListItemType.AlternatingItem) {
                OnFilterItemCreated(e.Item);
            }
        }
 
        private void Page_InitComplete(object sender, EventArgs e) {
            // We need to do this in InitComplete rather than Init to allow the user to set the
            // TableName in Page_Init
            DataSource = GetFilteredColumns();
            DataBind();
        }
 
        #region IWhereParametersProvider Members
 
        /// <summary>
        /// See IWhereParametersProvider
        /// </summary>
        public virtual IEnumerable<Parameter> GetWhereParameters(IDynamicDataSource dataSource) {
            // Add all the specific filters as where parameters
            return GetFilterControls().Select(filter => (Parameter)new DynamicControlParameter(filter.UniqueID) {
                Name = filter.DataField,
            });
        }
 
        #endregion
    }
}