-//\r
-// System.Data.DataView.cs\r
-//\r
-// Author:\r
-// Daniel Morgan <danmorg@sc.rr.com>\r
-// Tim Coleman (tim@timcoleman.com)\r
-// Punit Todi (punits_mailbox@yahoo.com)\r
-// Copyright (C) Daniel Morgan, 2002, 2003\r
-// (C) Ximian, Inc 2002\r
-// Copyright (C) Tim Coleman, 2002-2003 \r
-\r
-using System;\r
-using System.Collections;\r
-using System.ComponentModel;\r
-using System.Reflection;\r
-\r
-namespace System.Data \r
-{\r
- /// <summary>\r
- /// A DataView is used in the binding of data between\r
- /// a DataTable and Windows Forms or Web Forms allowing\r
- /// a view of a DataTable for editing, filtering,\r
- /// navigation, searching, and sorting.\r
- /// </summary>\r
- //[Designer]\r
- [Editor]\r
- [DefaultEvent ("PositionChanged")]\r
- [DefaultProperty ("Table")]\r
- [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.DataViewDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")]\r
- public class DataView : MarshalByValueComponent, IBindingList, IList, ICollection, IEnumerable, ITypedList, ISupportInitialize\r
- {\r
- DataTable dataTable = null;\r
- string rowFilter = "";\r
- string sort = "";\r
- DataViewRowState rowState;\r
- DataRowView[] rowCache = new DataRowView[0];\r
- \r
- \r
- bool allowNew = true; \r
- bool allowEdit = true;\r
- bool allowDelete = true;\r
- bool applyDefaultSort = false;\r
- bool isSorted = false;\r
-\r
- bool isOpen = false;\r
-\r
- bool bInit = false;\r
- bool useDefaultSort = true;\r
- \r
- internal DataViewManager dataViewManager = null;\r
- #region Constructors\r
- public DataView () \r
- {\r
- rowState = DataViewRowState.CurrentRows;\r
- Open ();\r
- }\r
-\r
- public DataView (DataTable table) \r
- {\r
- dataTable = table;\r
- rowState = DataViewRowState.CurrentRows;\r
- Open ();\r
- }\r
-\r
- public DataView (DataTable table, string RowFilter,\r
- string Sort, DataViewRowState RowState) \r
- {\r
- dataTable = table;\r
- rowState = DataViewRowState.CurrentRows;\r
- rowFilter = RowFilter;\r
- sort = Sort;\r
- rowState = RowState;\r
- Open();\r
- }\r
- #endregion // Constructors\r
- #region PublicProperties\r
- [DataCategory ("Data")]\r
- [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows deletes.")]\r
- [DefaultValue (true)]\r
- public bool AllowDelete {\r
- get {\r
- return allowDelete;\r
- }\r
- set {\r
- allowDelete = value;\r
- }\r
- }\r
-\r
- [DataCategory ("Data")]\r
- [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows edits.")]\r
- [DefaultValue (true)]\r
- public bool AllowEdit {\r
- get {\r
- return allowEdit;\r
- }\r
- set {\r
- allowEdit = value;\r
- }\r
- }\r
-\r
- [DataCategory ("Data")]\r
- [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows new rows to be added.")]\r
- [DefaultValue (true)]\r
- public bool AllowNew {\r
- get {\r
- return allowNew;\r
- }\r
- \r
- set {\r
- allowNew = value;\r
- }\r
- }\r
-\r
- [DataCategory ("Data")]\r
- [DataSysDescription ("Indicates whether to use the default sort if the Sort property is not set.")]\r
- [DefaultValue (false)]\r
- [RefreshProperties (RefreshProperties.All)]\r
- public bool ApplyDefaultSort {\r
- [MonoTODO]\r
- get { \r
- return applyDefaultSort;\r
- }\r
- \r
- [MonoTODO]\r
- set {\r
- applyDefaultSort = value;\r
- if (applyDefaultSort == true && (sort == null || sort == string.Empty)) {\r
- foreach (Constraint c in dataTable.Constraints) {\r
- if (c is UniqueConstraint) {\r
- sort = GetSortString ((UniqueConstraint) c);\r
- break;\r
- }\r
- }\r
- }\r
- UpdateIndex ();\r
- OnListChanged (new ListChangedEventArgs (ListChangedType.Reset,-1,-1));\r
- }\r
- }\r
- // get the count of rows in the DataView after RowFilter \r
- // and RowStateFilter have been applied\r
- [Browsable (false)]\r
- [DataSysDescription ("Returns the number of items currently in this view.")]\r
- public int Count {\r
- [MonoTODO]\r
- get {\r
- return rowCache.Length;\r
- }\r
- }\r
-\r
- [Browsable (false)]\r
- [DataSysDescription ("This returns a pointer to back to the DataViewManager that owns this DataSet (if any).")]\r
- public DataViewManager DataViewManager {\r
- [MonoTODO]\r
- get {\r
- return dataViewManager;\r
- }\r
- }\r
-\r
- // Item indexer\r
- // the compiler creates a DefaultMemeberAttribute from\r
- // this IndexerNameAttribute\r
- [System.Runtime.CompilerServices.IndexerName("Item")]\r
- public DataRowView this[int recordIndex] {\r
- [MonoTODO]\r
- get {\r
- return rowCache [recordIndex];\r
- }\r
- }\r
-\r
- [DataCategory ("Data")]\r
- [DataSysDescription ("Indicates an expression used to filter the data returned by this DataView.")]\r
- [DefaultValue ("")]\r
- public virtual string RowFilter {\r
- [MonoTODO]\r
- get {\r
- return rowFilter;\r
- }\r
- \r
- [MonoTODO]\r
- set {\r
- rowFilter = value;\r
- UpdateIndex ();\r
- OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, - 1, -1));\r
- }\r
- }\r
-\r
- [DataCategory ("Data")]\r
- [DataSysDescription ("Indicates the versions of data returned by this DataView.")]\r
- [DefaultValue (DataViewRowState.CurrentRows)]\r
- public DataViewRowState RowStateFilter {\r
- [MonoTODO]\r
- get {\r
- return rowState;\r
- }\r
- \r
- [MonoTODO]\r
- set {\r
- rowState = value;\r
- UpdateIndex ();\r
- OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, - 1, -1));\r
- }\r
- }\r
-\r
- [DataCategory ("Data")]\r
- [DataSysDescription ("Indicates the order in which data is returned by this DataView.")]\r
- [DefaultValue ("")]\r
- public string Sort {\r
- [MonoTODO]\r
- get {\r
- return sort;\r
- }\r
- \r
- [MonoTODO]\r
- set {\r
- if (value == null) { \r
- /* if given value is null useDefaultSort */\r
- useDefaultSort = true;\r
- /* if ApplyDefault sort is true try appling it */\r
- if (ApplyDefaultSort == true) {\r
- foreach (Constraint c in dataTable.Constraints) {\r
- if (c is UniqueConstraint) {\r
- sort = GetSortString ((UniqueConstraint)c);\r
- break;\r
- }\r
- }\r
- \r
- }\r
- }\r
- else { \r
- /* else donot useDefaultSort. set it as false */\r
- /* sort is set to value specified */\r
- useDefaultSort = false;\r
- sort = value;\r
- }\r
- UpdateIndex ();\r
- OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, - 1, -1));\r
- }\r
- }\r
-\r
- [DataCategory ("Data")]\r
- [DataSysDescription ("Indicates the table this DataView uses to get data.")]\r
- [DefaultValue (null)]\r
- [RefreshProperties (RefreshProperties.All)]\r
- public DataTable Table {\r
- [MonoTODO]\r
- get {\r
- return dataTable;\r
- }\r
- \r
- [MonoTODO]\r
- set {\r
- if (value != null && value.TableName.Equals("")) {\r
- throw new DataException("Cannot bind to DataTable with no name.");\r
- }\r
-\r
- if (dataTable != null) {\r
- UnregisterEventHandlers();\r
- }\r
-\r
- dataTable = value;\r
-\r
- if (dataTable != null) {\r
- RegisterEventHandlers();\r
- UpdateIndex ();\r
- OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, - 1, -1));\r
- }\r
- }\r
- }\r
- #endregion // PublicProperties\r
- \r
- #region PublicMethods\r
- [MonoTODO]\r
- public virtual DataRowView AddNew() \r
- {\r
- if (!IsOpen)\r
- throw new DataException ("DataView is not open.");\r
- if (!AllowNew)\r
- throw new DataException ("Cannot call AddNew on a DataView where AllowNew is false.");\r
- \r
- DataRow row = dataTable.NewRow ();\r
- if (row == null)\r
- throw new Exception ("Row not created");\r
- DataRowView rowView = new DataRowView (this, row, true);\r
- \r
- dataTable.Rows.Add (row);\r
- return rowView;\r
- }\r
-\r
- [MonoTODO]\r
- public void BeginInit() \r
- {\r
- bInit = true; \r
- // FIXME:\r
- }\r
-\r
- [MonoTODO]\r
- public void CopyTo (Array array, int index) \r
- {\r
- int row = 0;\r
- for (; row < rowCache.Length && row < array.Length; row++) {\r
- array.SetValue (rowCache[row], index + row);\r
- }\r
- }\r
-\r
- public void Delete(int index) \r
- {\r
- if (!IsOpen)\r
- throw new DataException ("DataView is not open.");\r
- if (!AllowDelete)\r
- throw new DataException ("Cannot delete on a DataSource where AllowDelete is false.");\r
- \r
- if (index > rowCache.Length)\r
- throw new IndexOutOfRangeException ("There is no row at " +\r
- "position: " + index + ".");\r
- DataRowView row = rowCache [index];\r
- row.Row.Delete ();\r
- }\r
-\r
-#if NET_2_0\r
- [MonoTODO]\r
- public virtual bool Equals (DataView dv)\r
- {\r
- throw new NotImplementedException ();\r
- }\r
-#endif\r
-\r
- [MonoTODO]\r
- public void EndInit() \r
- {\r
- bInit = false;\r
- // FIXME:\r
- }\r
-\r
- public int Find(object key) \r
- {\r
- object [] keys = new object[1];\r
- keys[0] = key;\r
- return Find(keys);\r
- }\r
- \r
- public int Find(object[] key) \r
- {\r
- int index; \r
- if (sort == null || sort == string.Empty)\r
- throw new ArgumentException ("Find finds a row based on a Sort order, and no Sort order is specified");\r
- else {\r
- DataTable.SortableColumn [] sortedColumns = null;\r
- sortedColumns = dataTable.ParseTheSortString (sort);\r
- if (sortedColumns == null)\r
- throw new Exception ("sort expression result is null");\r
- if (sortedColumns.Length == 0)\r
- throw new Exception ("sort expression result is 0");\r
- if (sortedColumns.Length != key.Length)\r
- throw new ArgumentException ("Expecting " + sortedColumns.Length +\r
- " value(s) from the key being indexed, but recieved "+\r
- key.Length+" value(s).");\r
- RowComparer rowComparer = new RowComparer (dataTable,sortedColumns);\r
- int searchResult = Array.BinarySearch (rowCache,key,rowComparer);\r
- if (searchResult < 0)\r
- return -1;\r
- else\r
- return searchResult;\r
- }\r
- }\r
- \r
- [MonoTODO]\r
- public DataRowView[] FindRows(object key) \r
- {\r
- // FIXME: use an index cache to the DataTable, and \r
- // only refresh the index when the DataTable\r
- // has changes via column, row, or constraint\r
- // changed events\r
-\r
- throw new NotImplementedException ();\r
- }\r
-\r
- [MonoTODO]\r
- public DataRowView[] FindRows(object[] key) \r
- {\r
- // FIXME: use an index cache to the DataTable, and \r
- // only refresh the index when the DataTable\r
- // has changes via column, row, or constraint\r
- // changed events\r
- \r
- throw new NotImplementedException ();\r
- }\r
-\r
- [MonoTODO]\r
- public IEnumerator GetEnumerator() \r
- {\r
- return new DataViewEnumerator (rowCache);\r
- }\r
- #endregion // PublicMethods\r
- \r
- [MonoTODO]\r
- [DataCategory ("Data")]\r
- [DataSysDescription ("Indicates the data returned by this DataView has somehow changed.")]\r
- public event ListChangedEventHandler ListChanged;\r
-\r
- protected bool IsOpen {\r
- [MonoTODO]\r
- get {\r
- return isOpen;\r
- }\r
- }\r
-\r
- [MonoTODO]\r
- protected void Close() \r
- {\r
- // FIXME:\r
- isOpen = false;\r
- }\r
-\r
- [MonoTODO]\r
- protected virtual void ColumnCollectionChanged (object sender, \r
- CollectionChangeEventArgs e) \r
- {\r
- throw new NotImplementedException ();\r
- }\r
-\r
- protected override void Dispose (bool disposing) \r
- {\r
- if (disposing)\r
- Close ();\r
-\r
- base.Dispose (disposing);\r
- }\r
-\r
- [MonoTODO]\r
- protected virtual void IndexListChanged(object sender, ListChangedEventArgs e) \r
- {\r
- throw new NotImplementedException ();\r
- }\r
-\r
- [MonoTODO]\r
- protected virtual void OnListChanged(ListChangedEventArgs e) \r
- {\r
- try {\r
- if (ListChanged != null)\r
- ListChanged (this, e);\r
- } catch {\r
- }\r
- }\r
-\r
- internal void ChangedList(ListChangedType listChangedType, int newIndex,int oldIndex)\r
- {\r
- ListChangedEventArgs e = new ListChangedEventArgs(listChangedType,newIndex,oldIndex);\r
- OnListChanged(e);\r
- }\r
-\r
- [MonoTODO]\r
- protected void Open() \r
- {\r
- // FIXME: create the initial index cache to the DataTable, and \r
- // only refresh the index when the DataTable\r
- // has changes via column, row, or constraint\r
- // changed events. the index cache is generally\r
- // a DataViewRow array that points to the actual\r
- // DataRows in the this DataTable's DataRowCollection;\r
- // this index is really a cache that gets \r
- // created during Open(), gets Updated \r
- // when various properties of this view\r
- // changes, gets Updated when this DataTable's \r
- // row, column, or constraint collections have changed.\r
- // I'm not sure what else.\r
- // The data view will know one of the DataTable's\r
- // collections have changed via one of \r
- // its changed events.\r
- // Otherwise, if getting a/the DataRowView(s),\r
- // Count, or other properties, then just use the\r
- // index cache.\r
- // dataTable.ColumnChanged += new DataColumnChangeEventHandler(OnColumnChanged);\r
- if (dataTable != null) {\r
- RegisterEventHandlers();\r
- UpdateIndex (true);\r
- }\r
- isOpen = true;\r
- }\r
- \r
- private void RegisterEventHandlers()\r
- {\r
- dataTable.RowChanged += new DataRowChangeEventHandler(OnRowChanged);\r
- dataTable.RowDeleted += new DataRowChangeEventHandler(OnRowDeleted);\r
- dataTable.Columns.CollectionChanged += new CollectionChangeEventHandler(OnColumnCollectionChanged);\r
- dataTable.Constraints.CollectionChanged += new CollectionChangeEventHandler(OnConstraintCollectionChanged);\r
- }\r
-\r
- private void UnregisterEventHandlers()\r
- {\r
- dataTable.RowChanged -= new DataRowChangeEventHandler(OnRowChanged);\r
- dataTable.RowDeleted -= new DataRowChangeEventHandler(OnRowDeleted);\r
- dataTable.Columns.CollectionChanged -= new CollectionChangeEventHandler(OnColumnCollectionChanged);\r
- dataTable.Constraints.CollectionChanged -= new CollectionChangeEventHandler(OnConstraintCollectionChanged);\r
- }\r
- \r
- private void OnColumnChanged(object sender, DataColumnChangeEventArgs args)\r
- { /* not used */\r
- UpdateIndex(true);\r
- }\r
- \r
- private void OnRowChanged(object sender, DataRowChangeEventArgs args)\r
- {\r
- int oldIndex,newIndex;\r
- oldIndex = newIndex = -1;\r
- oldIndex = IndexOf (args.Row);\r
- UpdateIndex (true);\r
- newIndex = IndexOf (args.Row);\r
-\r
- /* ItemAdded */\r
- if(args.Action == DataRowAction.Add)\r
- { \r
- OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, newIndex, -1));\r
- }\r
- \r
- /* ItemChanged or ItemMoved */\r
- if (args.Action == DataRowAction.Change) { \r
- if (oldIndex == newIndex)\r
- OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, newIndex, -1)); \r
- else\r
- OnListChanged (new ListChangedEventArgs (ListChangedType.ItemMoved, newIndex, oldIndex)); \r
- }\r
- }\r
- \r
- private void OnRowDeleted (object sender, DataRowChangeEventArgs args)\r
- {\r
- /* ItemDeleted */\r
- int newIndex;\r
- newIndex = IndexOf (args.Row);\r
- UpdateIndex (true);\r
- OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, newIndex, -1));\r
- }\r
- \r
- private void OnColumnCollectionChanged (object sender, CollectionChangeEventArgs args)\r
- {\r
- UpdateIndex (true);\r
- /* PropertyDescriptor Add */\r
- if (args.Action == CollectionChangeAction.Add)\r
- OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorAdded,0,0));\r
- /* PropertyDescriptor Removed */\r
- if (args.Action == CollectionChangeAction.Remove)\r
- OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorDeleted,0,0));\r
- /* FIXME: PropertyDescriptor Changed ???*/\r
- if (args.Action == CollectionChangeAction.Refresh)\r
- OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorChanged,0,0));\r
- }\r
- private void OnConstraintCollectionChanged(object sender, CollectionChangeEventArgs args)\r
- {\r
- // The Sort variable is set to the UniqueConstraint column.\r
- // if ApplyDefault Sort is true and Sort is null or is not set Explicitly\r
- \r
- // FIXME: The interal cache may change as result of change in Constraint collection\r
- // one such scenerio is taken care.\r
- // There may be more. I dont know what else can be done.\r
- /* useDefaultSort is set to false when Sort is set explicitly */\r
- if (args.Action == CollectionChangeAction.Add && args.Element is UniqueConstraint) {\r
- if (ApplyDefaultSort == true && useDefaultSort == true)\r
- Sort = GetSortString ((UniqueConstraint) args.Element);\r
- }\r
- UpdateIndex (true);\r
- /* ItemReset */\r
- OnListChanged (new ListChangedEventArgs (ListChangedType.Reset,-1,-1));\r
- }\r
-\r
- // internal use by Mono\r
- protected void Reset() \r
- {\r
- // TODO: what really happens?\r
- Close ();\r
- rowCache = new DataRowView[0];\r
- Open ();\r
- OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1 ));\r
- }\r
-\r
-#if NET_2_0\r
- [MonoTODO]\r
- public DataTable ToTable ()\r
- {\r
- throw new NotImplementedException ();\r
- }\r
-\r
- [MonoTODO]\r
- public DataTable ToTable (bool isDistinct, string[] columnNames)\r
- {\r
- throw new NotImplementedException ();\r
- }\r
-#endif\r
-\r
- // internal use by Mono\r
- protected virtual void UpdateIndex () \r
- {\r
- UpdateIndex (false);\r
- }\r
-\r
- // This is method is internal to \r
- // the Mono implementation of DataView; it\r
- // is not to be used from your code.\r
- //\r
- // Update the DataRowView array which is an index cache\r
- // into the DataTable's DataRowCollection.\r
- //\r
- // I assume this is what UpdateIndex is used for\r
- protected virtual void UpdateIndex(bool force) \r
- {\r
- DataRowView[] newRowCache = null;\r
- DataRow[] rows = null;\r
- \r
- rows = dataTable.Select (RowFilter, Sort, RowStateFilter);\r
-\r
- newRowCache = new DataRowView[rows.Length];\r
- for (int r = 0; r < rows.Length; r++) {\r
- newRowCache[r] = new DataRowView (this, rows[r]);\r
- }\r
- rowCache = newRowCache;\r
- }\r
-\r
- [MonoTODO]\r
- PropertyDescriptorCollection ITypedList.GetItemProperties (PropertyDescriptor[] listAccessors) \r
- {\r
- // FIXME: use listAccessors somehow\r
- DataColumnPropertyDescriptor [] descriptors = \r
- new DataColumnPropertyDescriptor [dataTable.Columns.Count];\r
-\r
- DataColumnPropertyDescriptor descriptor;\r
- DataColumn dataColumn;\r
- for (int col = 0; col < dataTable.Columns.Count; col ++) {\r
- dataColumn = dataTable.Columns[col];\r
- descriptor = new DataColumnPropertyDescriptor(\r
- dataColumn.ColumnName, col, null);\r
- descriptor.SetComponentType (typeof (System.Data.DataRowView));\r
- descriptor.SetPropertyType (dataColumn.DataType);\r
- descriptor.SetReadOnly (dataColumn.ReadOnly);\r
- descriptors [col] = descriptor;\r
- }\r
- return new PropertyDescriptorCollection (descriptors);\r
- }\r
-\r
- [MonoTODO]\r
- string ITypedList.GetListName (PropertyDescriptor[] listAccessors) \r
- {\r
- return "";\r
- }\r
-\r
- //int ICollection.Count { \r
- // get {\r
- // return Count;\r
- // } \r
- //}\r
-\r
- bool ICollection.IsSynchronized { \r
- [MonoTODO]\r
- get {\r
- return false;\r
- } \r
- }\r
-\r
- object ICollection.SyncRoot { \r
- [MonoTODO]\r
- get {\r
- // FIXME:\r
- return this;\r
- }\r
- }\r
-\r
- //void ICollection.CopyTo (Array array, int index) \r
- //{\r
- // CopyTo (array, index);\r
- //}\r
-\r
- bool IList.IsFixedSize {\r
- [MonoTODO]\r
- get {\r
- return false;\r
- }\r
- }\r
- \r
- bool IList.IsReadOnly {\r
- [MonoTODO]\r
- get {\r
- return false;\r
- }\r
- }\r
-\r
- object IList.this[int recordIndex] {\r
- [MonoTODO]\r
- get {\r
- return this[recordIndex];\r
- }\r
-\r
- [MonoTODO]\r
- set{\r
- throw new InvalidOperationException();\r
- }\r
- }\r
-\r
- [MonoTODO]\r
- int IList.Add (object value) \r
- {\r
- throw new NotImplementedException ();\r
- }\r
-\r
- [MonoTODO]\r
- void IList.Clear () \r
- {\r
- throw new NotImplementedException ();\r
- }\r
-\r
- [MonoTODO]\r
- bool IList.Contains (object value) \r
- {\r
- throw new NotImplementedException ();\r
- }\r
-\r
- [MonoTODO]\r
- int IList.IndexOf (object value) \r
- {\r
- throw new NotImplementedException ();\r
- }\r
- \r
- [MonoTODO]\r
- void IList.Insert(int index,object value) \r
- {\r
- throw new NotImplementedException ();\r
- }\r
-\r
- [MonoTODO]\r
- void IList.Remove(object value) \r
- {\r
- throw new NotImplementedException ();\r
- }\r
-\r
- [MonoTODO]\r
- void IList.RemoveAt(int index) \r
- {\r
- throw new NotImplementedException ();\r
- }\r
-\r
- #region IBindingList implementation\r
-\r
- [MonoTODO]\r
- void IBindingList.AddIndex (PropertyDescriptor property) \r
- {\r
- throw new NotImplementedException ();\r
- }\r
-\r
- [MonoTODO]\r
- object IBindingList.AddNew () \r
- {\r
- throw new NotImplementedException ();\r
- }\r
-\r
- [MonoTODO]\r
- void IBindingList.ApplySort (PropertyDescriptor property, ListSortDirection direction) \r
- {\r
- throw new NotImplementedException ();\r
- }\r
-\r
- [MonoTODO]\r
- int IBindingList.Find (PropertyDescriptor property, object key) \r
- {\r
- throw new NotImplementedException ();\r
- }\r
-\r
- [MonoTODO]\r
- void IBindingList.RemoveIndex (PropertyDescriptor property) \r
- {\r
- throw new NotImplementedException ();\r
- }\r
-\r
- [MonoTODO]\r
- void IBindingList.RemoveSort () \r
- {\r
- throw new NotImplementedException ();\r
- }\r
- \r
- bool IBindingList.AllowEdit {\r
- [MonoTODO]\r
- get {\r
- return AllowEdit;\r
- }\r
- }\r
-\r
- bool IBindingList.AllowNew {\r
- [MonoTODO]\r
- get {\r
- return AllowNew;\r
- }\r
- }\r
-\r
- bool IBindingList.AllowRemove {\r
- [MonoTODO]\r
- get {\r
- return AllowDelete;\r
- }\r
- }\r
-\r
- bool IBindingList.IsSorted {\r
- [MonoTODO]\r
- get {\r
- return isSorted;\r
- }\r
- }\r
-\r
- ListSortDirection IBindingList.SortDirection {\r
- [MonoTODO]\r
- get {\r
- // FIXME: \r
- return ListSortDirection.Ascending;\r
- }\r
- }\r
-\r
- PropertyDescriptor IBindingList.SortProperty {\r
- [MonoTODO]\r
- get {\r
- // FIXME:\r
- return null;\r
- }\r
- }\r
-\r
- bool IBindingList.SupportsChangeNotification {\r
- [MonoTODO]\r
- get {\r
- return false;\r
- }\r
- }\r
-\r
- bool IBindingList.SupportsSearching {\r
- [MonoTODO]\r
- get {\r
- return false;\r
- }\r
- }\r
-\r
- bool IBindingList.SupportsSorting {\r
- [MonoTODO]\r
- get {\r
- return false;\r
- }\r
- }\r
-\r
- #endregion // IBindingList implementation\r
- private int IndexOf(DataRow dr)\r
- {\r
- for (int i=0; i < rowCache.Length; i++)\r
- if (dr.Equals (rowCache [i].Row))\r
- return i;\r
- return -1;\r
- }\r
- \r
- private string GetSortString (UniqueConstraint uc)\r
- {\r
- string sortKey = null;\r
- foreach (DataColumn dc in uc.Columns)\r
- sortKey += dc.ColumnName + ", ";\r
- sortKey = sortKey.Substring (0,sortKey.Length - 2);\r
- return sortKey;\r
- }\r
- \r
- private object [] GetSearchKey (DataRow dr)\r
- {\r
- DataTable.SortableColumn [] sortedColumns = null;\r
- sortedColumns = dataTable.ParseTheSortString (sort);\r
- if (sortedColumns == null) \r
- return null;\r
- object [] keys = new object [sortedColumns.Length];\r
- int i = 0;\r
- foreach (DataTable.SortableColumn sc in sortedColumns) {\r
- keys [i] = dr [sc.Column];\r
- i++;\r
- }\r
- return keys;\r
- }\r
-\r
- private class DataViewEnumerator : IEnumerator \r
- {\r
- private DataRowView [] rows;\r
- int on = -1;\r
-\r
- internal DataViewEnumerator (DataRowView [] dataRowViews) \r
- {\r
- rows = dataRowViews;\r
- }\r
-\r
- public object Current {\r
- get {\r
- if (on == -1 || on >= rows.Length)\r
- throw new InvalidOperationException ();\r
- return rows [on];\r
- }\r
- }\r
-\r
- public bool MoveNext () \r
- {\r
- // TODO: how do you determine\r
- // if a collection has been\r
- // changed?\r
- if (on < rows.Length - 1) {\r
- on++;\r
- return true;\r
- }\r
-\r
- return false; // EOF\r
- }\r
-\r
- public void Reset () {\r
- on = -1;\r
- }\r
- }\r
- \r
- private class RowComparer : IComparer \r
- {\r
- private DataTable.SortableColumn [] sortColumns;\r
- private DataTable table;\r
- public RowComparer(DataTable table, DataTable.SortableColumn[] sortColumns) \r
- {\r
- this.table = table; \r
- this.sortColumns = sortColumns;\r
- }\r
-\r
- public DataTable.SortableColumn[] SortedColumns {\r
- get {\r
- return sortColumns;\r
- }\r
- }\r
- \r
- int IComparer.Compare (object x, object y) \r
- {\r
- if(x == null)\r
- throw new Exception ("Object to compare is null: x");\r
- if(y == null)\r
- throw new Exception ("Object to compare is null: y");\r
- DataRowView rowView = (DataRowView) y;\r
- object [] keys = (object [])x;\r
- for(int i = 0; i < sortColumns.Length; i++) {\r
- DataTable.SortableColumn sortColumn = sortColumns [i];\r
- DataColumn dc = sortColumn.Column;\r
-\r
- IComparable row = (IComparable) rowView.Row [dc];\r
- object key = keys [i];\r
- \r
- int result = CompareObjects (key,row);\r
- if (result != 0) {\r
- if (sortColumn.SortDirection == ListSortDirection.Ascending)\r
- return result;\r
- else \r
- return -result;\r
- }\r
- }\r
- return 0;\r
- }\r
-\r
- private int CompareObjects (object a, object b) \r
- {\r
- if (a == b)\r
- return 0;\r
- else if (a == null)\r
- return -1;\r
- else if (a == DBNull.Value)\r
- return -1;\r
- else if (b == null)\r
- return 1;\r
- else if (b == DBNull.Value)\r
- return 1;\r
-\r
- if((a is string) && (b is string)) {\r
- a = ((string) a).ToUpper (table.Locale);\r
- b = ((string) b).ToUpper (table.Locale); \r
- }\r
-\r
- if (a is IComparable)\r
- return ((a as IComparable).CompareTo (b));\r
- else if (b is IComparable)\r
- return -((b as IComparable).CompareTo (a));\r
-\r
- throw new ArgumentException ("Neither a nor b IComparable");\r
- }\r
- }\r
-\r
- }\r
-}\r
+//
+// System.Data.DataView.cs
+//
+// Author:
+// Daniel Morgan <danmorg@sc.rr.com>
+// Tim Coleman (tim@timcoleman.com)
+// Punit Todi (punits_mailbox@yahoo.com)
+// Copyright (C) Daniel Morgan, 2002, 2003
+// (C) Ximian, Inc 2002
+// Copyright (C) Tim Coleman, 2002-2003
+
+using System;
+using System.Collections;
+using System.ComponentModel;
+using System.Reflection;
+using Mono.Data.SqlExpressions;
+
+namespace System.Data
+{
+ /// <summary>
+ /// A DataView is used in the binding of data between
+ /// a DataTable and Windows Forms or Web Forms allowing
+ /// a view of a DataTable for editing, filtering,
+ /// navigation, searching, and sorting.
+ /// </summary>
+ //[Designer]
+ [Editor]
+ [DefaultEvent ("PositionChanged")]
+ [DefaultProperty ("Table")]
+ [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.DataViewDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")]
+ public class DataView : MarshalByValueComponent, IBindingList, IList, ICollection, IEnumerable, ITypedList, ISupportInitialize
+ {
+ DataTable dataTable = null;
+ string rowFilter = "";
+ IExpression rowFilterExpr;
+ string sort = "";
+ SortableColumn [] sortedColumns = null;
+ DataViewRowState rowState;
+ DataRowView[] rowCache = new DataRowView[0];
+
+ bool allowNew = true;
+ bool allowEdit = true;
+ bool allowDelete = true;
+ bool applyDefaultSort = false;
+ bool isSorted = false;
+
+ bool isOpen = false;
+
+ bool bInit = false;
+ bool useDefaultSort = true;
+
+ internal DataViewManager dataViewManager = null;
+ #region Constructors
+ public DataView ()
+ {
+ rowState = DataViewRowState.CurrentRows;
+ Open ();
+ }
+
+ public DataView (DataTable table)
+ {
+ dataTable = table;
+ rowState = DataViewRowState.CurrentRows;
+ Open ();
+ }
+
+ public DataView (DataTable table, string RowFilter,
+ string Sort, DataViewRowState RowState)
+ {
+ dataTable = table;
+ rowState = DataViewRowState.CurrentRows;
+ this.RowFilter = RowFilter;
+ this.Sort = Sort;
+ rowState = RowState;
+ Open();
+ }
+ #endregion // Constructors
+ #region PublicProperties
+ [DataCategory ("Data")]
+ [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows deletes.")]
+ [DefaultValue (true)]
+ public bool AllowDelete {
+ get {
+ return allowDelete;
+ }
+ set {
+ allowDelete = value;
+ }
+ }
+
+ [DataCategory ("Data")]
+ [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows edits.")]
+ [DefaultValue (true)]
+ public bool AllowEdit {
+ get {
+ return allowEdit;
+ }
+ set {
+ allowEdit = value;
+ }
+ }
+
+ [DataCategory ("Data")]
+ [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows new rows to be added.")]
+ [DefaultValue (true)]
+ public bool AllowNew {
+ get {
+ return allowNew;
+ }
+
+ set {
+ allowNew = value;
+ }
+ }
+
+ [DataCategory ("Data")]
+ [DataSysDescription ("Indicates whether to use the default sort if the Sort property is not set.")]
+ [DefaultValue (false)]
+ [RefreshProperties (RefreshProperties.All)]
+ public bool ApplyDefaultSort {
+ [MonoTODO]
+ get {
+ return applyDefaultSort;
+ }
+
+ [MonoTODO]
+ set {
+ applyDefaultSort = value;
+ if (applyDefaultSort == true && (sort == null || sort == string.Empty)) {
+ foreach (Constraint c in dataTable.Constraints) {
+ if (c is UniqueConstraint) {
+ // FIXME: Compute SortableColumns[] directly.
+ Sort = GetSortString ((UniqueConstraint) c);
+ break;
+ }
+ }
+ }
+ UpdateIndex ();
+ OnListChanged (new ListChangedEventArgs (ListChangedType.Reset,-1,-1));
+ }
+ }
+ // get the count of rows in the DataView after RowFilter
+ // and RowStateFilter have been applied
+ [Browsable (false)]
+ [DataSysDescription ("Returns the number of items currently in this view.")]
+ public int Count {
+ [MonoTODO]
+ get {
+ return rowCache.Length;
+ }
+ }
+
+ [Browsable (false)]
+ [DataSysDescription ("This returns a pointer to back to the DataViewManager that owns this DataSet (if any).")]
+ public DataViewManager DataViewManager {
+ [MonoTODO]
+ get {
+ return dataViewManager;
+ }
+ }
+
+ // Item indexer
+ // the compiler creates a DefaultMemeberAttribute from
+ // this IndexerNameAttribute
+ [System.Runtime.CompilerServices.IndexerName("Item")]
+ public DataRowView this[int recordIndex] {
+ [MonoTODO]
+ get {
+ return rowCache [recordIndex];
+ }
+ }
+
+ [DataCategory ("Data")]
+ [DataSysDescription ("Indicates an expression used to filter the data returned by this DataView.")]
+ [DefaultValue ("")]
+ public virtual string RowFilter {
+ [MonoTODO]
+ get {
+ return rowFilter;
+ }
+
+ [MonoTODO]
+ set {
+ if (value == null)
+ value = String.Empty;
+ if (value == String.Empty)
+ rowFilterExpr = null;
+ else {
+ Parser parser = new Parser ();
+ rowFilterExpr = parser.Compile (value);
+ }
+ rowFilter = value;
+ UpdateIndex ();
+ OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, - 1, -1));
+ }
+ }
+
+ [DataCategory ("Data")]
+ [DataSysDescription ("Indicates the versions of data returned by this DataView.")]
+ [DefaultValue (DataViewRowState.CurrentRows)]
+ public DataViewRowState RowStateFilter {
+ [MonoTODO]
+ get {
+ return rowState;
+ }
+
+ [MonoTODO]
+ set {
+ rowState = value;
+ UpdateIndex ();
+ OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, - 1, -1));
+ }
+ }
+
+ [DataCategory ("Data")]
+ [DataSysDescription ("Indicates the order in which data is returned by this DataView.")]
+ [DefaultValue ("")]
+ public string Sort {
+ [MonoTODO]
+ get {
+ return sort;
+ }
+
+ [MonoTODO]
+ set {
+ if (value == null) {
+ /* if given value is null useDefaultSort */
+ useDefaultSort = true;
+ /* if ApplyDefault sort is true try appling it */
+ if (ApplyDefaultSort == true) {
+ foreach (Constraint c in dataTable.Constraints) {
+ if (c is UniqueConstraint) {
+ // FIXME: Compute SortableColumns[] directly.
+ Sort = GetSortString ((UniqueConstraint)c);
+ break;
+ }
+ }
+
+ }
+ }
+ else {
+ /* else donot useDefaultSort. set it as false */
+ /* sort is set to value specified */
+ useDefaultSort = false;
+ sort = value;
+ sortedColumns = SortableColumn.ParseSortString (dataTable, value, true);
+ }
+ UpdateIndex ();
+ OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, - 1, -1));
+ }
+ }
+
+ [DataCategory ("Data")]
+ [DataSysDescription ("Indicates the table this DataView uses to get data.")]
+ [DefaultValue (null)]
+ [RefreshProperties (RefreshProperties.All)]
+ public DataTable Table {
+ [MonoTODO]
+ get {
+ return dataTable;
+ }
+
+ [MonoTODO]
+ set {
+ if (value != null && value.TableName.Equals("")) {
+ throw new DataException("Cannot bind to DataTable with no name.");
+ }
+
+ if (dataTable != null) {
+ UnregisterEventHandlers();
+ }
+
+ dataTable = value;
+
+ if (dataTable != null) {
+ RegisterEventHandlers();
+ UpdateIndex ();
+ OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, - 1, -1));
+ }
+ }
+ }
+ #endregion // PublicProperties
+
+ #region PublicMethods
+ [MonoTODO]
+ public virtual DataRowView AddNew()
+ {
+ if (!IsOpen)
+ throw new DataException ("DataView is not open.");
+ if (!AllowNew)
+ throw new DataException ("Cannot call AddNew on a DataView where AllowNew is false.");
+
+ DataRow row = dataTable.NewRow ();
+ if (row == null)
+ throw new Exception ("Row not created");
+ DataRowView rowView = new DataRowView (this, row, true);
+
+ dataTable.Rows.Add (row);
+ return rowView;
+ }
+
+ [MonoTODO]
+ public void BeginInit()
+ {
+ bInit = true;
+ // FIXME:
+ }
+
+ [MonoTODO]
+ public void CopyTo (Array array, int index)
+ {
+ int row = 0;
+ for (; row < rowCache.Length && row < array.Length; row++) {
+ array.SetValue (rowCache[row], index + row);
+ }
+ }
+
+ public void Delete(int index)
+ {
+ if (!IsOpen)
+ throw new DataException ("DataView is not open.");
+ if (!AllowDelete)
+ throw new DataException ("Cannot delete on a DataSource where AllowDelete is false.");
+
+ if (index > rowCache.Length)
+ throw new IndexOutOfRangeException ("There is no row at " +
+ "position: " + index + ".");
+ DataRowView row = rowCache [index];
+ row.Row.Delete ();
+ }
+
+#if NET_2_0
+ [MonoTODO]
+ public virtual bool Equals (DataView dv)
+ {
+ throw new NotImplementedException ();
+ }
+#endif
+
+ [MonoTODO]
+ public void EndInit()
+ {
+ bInit = false;
+ // FIXME:
+ }
+
+ public int Find(object key)
+ {
+ object [] keys = new object[1];
+ keys[0] = key;
+ return Find(keys);
+ }
+
+ public int Find(object[] key)
+ {
+ int index;
+ if (sort == null || sort == string.Empty)
+ throw new ArgumentException ("Find finds a row based on a Sort order, and no Sort order is specified");
+ else {
+ // FIXME: maybe some of those thecks could be removel.
+ if (sortedColumns == null)
+ throw new Exception ("sort expression result is null");
+ if (sortedColumns.Length == 0)
+ throw new Exception ("sort expression result is 0");
+ if (sortedColumns.Length != key.Length)
+ throw new ArgumentException ("Expecting " + sortedColumns.Length +
+ " value(s) from the key being indexed, but recieved "+
+ key.Length+" value(s).");
+ RowComparer rowComparer = new RowComparer (dataTable,sortedColumns);
+ int searchResult = Array.BinarySearch (rowCache,key,rowComparer);
+ if (searchResult < 0)
+ return -1;
+ else
+ return searchResult;
+ }
+ }
+
+ [MonoTODO]
+ public DataRowView[] FindRows(object key)
+ {
+ // FIXME: use an index cache to the DataTable, and
+ // only refresh the index when the DataTable
+ // has changes via column, row, or constraint
+ // changed events
+
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public DataRowView[] FindRows(object[] key)
+ {
+ // FIXME: use an index cache to the DataTable, and
+ // only refresh the index when the DataTable
+ // has changes via column, row, or constraint
+ // changed events
+
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public IEnumerator GetEnumerator()
+ {
+ return new DataViewEnumerator (rowCache);
+ }
+ #endregion // PublicMethods
+
+ [MonoTODO]
+ [DataCategory ("Data")]
+ [DataSysDescription ("Indicates the data returned by this DataView has somehow changed.")]
+ public event ListChangedEventHandler ListChanged;
+
+ protected bool IsOpen {
+ [MonoTODO]
+ get {
+ return isOpen;
+ }
+ }
+
+ [MonoTODO]
+ protected void Close()
+ {
+ // FIXME:
+ isOpen = false;
+ }
+
+ [MonoTODO]
+ protected virtual void ColumnCollectionChanged (object sender,
+ CollectionChangeEventArgs e)
+ {
+ throw new NotImplementedException ();
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ if (disposing)
+ Close ();
+
+ base.Dispose (disposing);
+ }
+
+ [MonoTODO]
+ protected virtual void IndexListChanged(object sender, ListChangedEventArgs e)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ protected virtual void OnListChanged(ListChangedEventArgs e)
+ {
+ try {
+ if (ListChanged != null)
+ ListChanged (this, e);
+ } catch {
+ }
+ }
+
+ internal void ChangedList(ListChangedType listChangedType, int newIndex,int oldIndex)
+ {
+ ListChangedEventArgs e = new ListChangedEventArgs(listChangedType,newIndex,oldIndex);
+ OnListChanged(e);
+ }
+
+ [MonoTODO]
+ protected void Open()
+ {
+ // FIXME: create the initial index cache to the DataTable, and
+ // only refresh the index when the DataTable
+ // has changes via column, row, or constraint
+ // changed events. the index cache is generally
+ // a DataViewRow array that points to the actual
+ // DataRows in the this DataTable's DataRowCollection;
+ // this index is really a cache that gets
+ // created during Open(), gets Updated
+ // when various properties of this view
+ // changes, gets Updated when this DataTable's
+ // row, column, or constraint collections have changed.
+ // I'm not sure what else.
+ // The data view will know one of the DataTable's
+ // collections have changed via one of
+ // its changed events.
+ // Otherwise, if getting a/the DataRowView(s),
+ // Count, or other properties, then just use the
+ // index cache.
+ // dataTable.ColumnChanged += new DataColumnChangeEventHandler(OnColumnChanged);
+ if (dataTable != null) {
+ RegisterEventHandlers();
+ UpdateIndex (true);
+ }
+ isOpen = true;
+ }
+
+ private void RegisterEventHandlers()
+ {
+ dataTable.RowChanged += new DataRowChangeEventHandler(OnRowChanged);
+ dataTable.RowDeleted += new DataRowChangeEventHandler(OnRowDeleted);
+ dataTable.Columns.CollectionChanged += new CollectionChangeEventHandler(OnColumnCollectionChanged);
+ dataTable.Constraints.CollectionChanged += new CollectionChangeEventHandler(OnConstraintCollectionChanged);
+ }
+
+ private void UnregisterEventHandlers()
+ {
+ dataTable.RowChanged -= new DataRowChangeEventHandler(OnRowChanged);
+ dataTable.RowDeleted -= new DataRowChangeEventHandler(OnRowDeleted);
+ dataTable.Columns.CollectionChanged -= new CollectionChangeEventHandler(OnColumnCollectionChanged);
+ dataTable.Constraints.CollectionChanged -= new CollectionChangeEventHandler(OnConstraintCollectionChanged);
+ }
+
+ private void OnColumnChanged(object sender, DataColumnChangeEventArgs args)
+ { /* not used */
+ UpdateIndex(true);
+ }
+
+ private void OnRowChanged(object sender, DataRowChangeEventArgs args)
+ {
+ int oldIndex,newIndex;
+ oldIndex = newIndex = -1;
+ oldIndex = IndexOf (args.Row);
+ UpdateIndex (true);
+ newIndex = IndexOf (args.Row);
+
+ /* ItemAdded */
+ if(args.Action == DataRowAction.Add)
+ {
+ OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, newIndex, -1));
+ }
+
+ /* ItemChanged or ItemMoved */
+ if (args.Action == DataRowAction.Change) {
+ if (oldIndex == newIndex)
+ OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, newIndex, -1));
+ else
+ OnListChanged (new ListChangedEventArgs (ListChangedType.ItemMoved, newIndex, oldIndex));
+ }
+ }
+
+ private void OnRowDeleted (object sender, DataRowChangeEventArgs args)
+ {
+ /* ItemDeleted */
+ int newIndex;
+ newIndex = IndexOf (args.Row);
+ UpdateIndex (true);
+ OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, newIndex, -1));
+ }
+
+ private void OnColumnCollectionChanged (object sender, CollectionChangeEventArgs args)
+ {
+ UpdateIndex (true);
+ /* PropertyDescriptor Add */
+ if (args.Action == CollectionChangeAction.Add)
+ OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorAdded,0,0));
+ /* PropertyDescriptor Removed */
+ if (args.Action == CollectionChangeAction.Remove)
+ OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorDeleted,0,0));
+ /* FIXME: PropertyDescriptor Changed ???*/
+ if (args.Action == CollectionChangeAction.Refresh)
+ OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorChanged,0,0));
+ }
+ private void OnConstraintCollectionChanged(object sender, CollectionChangeEventArgs args)
+ {
+ // The Sort variable is set to the UniqueConstraint column.
+ // if ApplyDefault Sort is true and Sort is null or is not set Explicitly
+
+ // FIXME: The interal cache may change as result of change in Constraint collection
+ // one such scenerio is taken care.
+ // There may be more. I dont know what else can be done.
+ /* useDefaultSort is set to false when Sort is set explicitly */
+ if (args.Action == CollectionChangeAction.Add && args.Element is UniqueConstraint) {
+ if (ApplyDefaultSort == true && useDefaultSort == true)
+ Sort = GetSortString ((UniqueConstraint) args.Element);
+ }
+ UpdateIndex (true);
+ /* ItemReset */
+ OnListChanged (new ListChangedEventArgs (ListChangedType.Reset,-1,-1));
+ }
+
+ // internal use by Mono
+ protected void Reset()
+ {
+ // TODO: what really happens?
+ Close ();
+ rowCache = new DataRowView[0];
+ Open ();
+ OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1 ));
+ }
+
+#if NET_2_0
+ [MonoTODO]
+ public DataTable ToTable ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public DataTable ToTable (bool isDistinct, string[] columnNames)
+ {
+ throw new NotImplementedException ();
+ }
+#endif
+
+ // internal use by Mono
+ protected virtual void UpdateIndex ()
+ {
+ UpdateIndex (false);
+ }
+
+ // This is method is internal to
+ // the Mono implementation of DataView; it
+ // is not to be used from your code.
+ //
+ // Update the DataRowView array which is an index cache
+ // into the DataTable's DataRowCollection.
+ //
+ // I assume this is what UpdateIndex is used for
+ protected virtual void UpdateIndex(bool force)
+ {
+ DataRowView[] newRowCache = null;
+ DataRow[] rows = null;
+
+ rows = dataTable.Select (rowFilterExpr, sortedColumns, RowStateFilter);
+
+ newRowCache = new DataRowView[rows.Length];
+ for (int r = 0; r < rows.Length; r++) {
+ newRowCache[r] = new DataRowView (this, rows[r]);
+ }
+ rowCache = newRowCache;
+ }
+
+ [MonoTODO]
+ PropertyDescriptorCollection ITypedList.GetItemProperties (PropertyDescriptor[] listAccessors)
+ {
+ // FIXME: use listAccessors somehow
+ DataColumnPropertyDescriptor [] descriptors =
+ new DataColumnPropertyDescriptor [dataTable.Columns.Count];
+
+ DataColumnPropertyDescriptor descriptor;
+ DataColumn dataColumn;
+ for (int col = 0; col < dataTable.Columns.Count; col ++) {
+ dataColumn = dataTable.Columns[col];
+ descriptor = new DataColumnPropertyDescriptor(
+ dataColumn.ColumnName, col, null);
+ descriptor.SetComponentType (typeof (System.Data.DataRowView));
+ descriptor.SetPropertyType (dataColumn.DataType);
+ descriptor.SetReadOnly (dataColumn.ReadOnly);
+ descriptors [col] = descriptor;
+ }
+ return new PropertyDescriptorCollection (descriptors);
+ }
+
+ [MonoTODO]
+ string ITypedList.GetListName (PropertyDescriptor[] listAccessors)
+ {
+ return "";
+ }
+
+ //int ICollection.Count {
+ // get {
+ // return Count;
+ // }
+ //}
+
+ bool ICollection.IsSynchronized {
+ [MonoTODO]
+ get {
+ return false;
+ }
+ }
+
+ object ICollection.SyncRoot {
+ [MonoTODO]
+ get {
+ // FIXME:
+ return this;
+ }
+ }
+
+ //void ICollection.CopyTo (Array array, int index)
+ //{
+ // CopyTo (array, index);
+ //}
+
+ bool IList.IsFixedSize {
+ [MonoTODO]
+ get {
+ return false;
+ }
+ }
+
+ bool IList.IsReadOnly {
+ [MonoTODO]
+ get {
+ return false;
+ }
+ }
+
+ object IList.this[int recordIndex] {
+ [MonoTODO]
+ get {
+ return this[recordIndex];
+ }
+
+ [MonoTODO]
+ set{
+ throw new InvalidOperationException();
+ }
+ }
+
+ [MonoTODO]
+ int IList.Add (object value)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ void IList.Clear ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ bool IList.Contains (object value)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ int IList.IndexOf (object value)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ void IList.Insert(int index,object value)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ void IList.Remove(object value)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ void IList.RemoveAt(int index)
+ {
+ throw new NotImplementedException ();
+ }
+
+ #region IBindingList implementation
+
+ [MonoTODO]
+ void IBindingList.AddIndex (PropertyDescriptor property)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ object IBindingList.AddNew ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ void IBindingList.ApplySort (PropertyDescriptor property, ListSortDirection direction)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ int IBindingList.Find (PropertyDescriptor property, object key)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ void IBindingList.RemoveIndex (PropertyDescriptor property)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ void IBindingList.RemoveSort ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ bool IBindingList.AllowEdit {
+ [MonoTODO]
+ get {
+ return AllowEdit;
+ }
+ }
+
+ bool IBindingList.AllowNew {
+ [MonoTODO]
+ get {
+ return AllowNew;
+ }
+ }
+
+ bool IBindingList.AllowRemove {
+ [MonoTODO]
+ get {
+ return AllowDelete;
+ }
+ }
+
+ bool IBindingList.IsSorted {
+ [MonoTODO]
+ get {
+ return isSorted;
+ }
+ }
+
+ ListSortDirection IBindingList.SortDirection {
+ [MonoTODO]
+ get {
+ // FIXME:
+ return ListSortDirection.Ascending;
+ }
+ }
+
+ PropertyDescriptor IBindingList.SortProperty {
+ [MonoTODO]
+ get {
+ // FIXME:
+ return null;
+ }
+ }
+
+ bool IBindingList.SupportsChangeNotification {
+ [MonoTODO]
+ get {
+ return false;
+ }
+ }
+
+ bool IBindingList.SupportsSearching {
+ [MonoTODO]
+ get {
+ return false;
+ }
+ }
+
+ bool IBindingList.SupportsSorting {
+ [MonoTODO]
+ get {
+ return false;
+ }
+ }
+
+ #endregion // IBindingList implementation
+ private int IndexOf(DataRow dr)
+ {
+ for (int i=0; i < rowCache.Length; i++)
+ if (dr.Equals (rowCache [i].Row))
+ return i;
+ return -1;
+ }
+
+ private string GetSortString (UniqueConstraint uc)
+ {
+ string sortKey = null;
+ foreach (DataColumn dc in uc.Columns)
+ sortKey += dc.ColumnName + ", ";
+ sortKey = sortKey.Substring (0,sortKey.Length - 2);
+ return sortKey;
+ }
+
+ private object [] GetSearchKey (DataRow dr)
+ {
+ if (sortedColumns == null)
+ return null;
+ object [] keys = new object [sortedColumns.Length];
+ int i = 0;
+ foreach (SortableColumn sc in sortedColumns) {
+ keys [i] = dr [sc.Column];
+ i++;
+ }
+ return keys;
+ }
+
+ private class DataViewEnumerator : IEnumerator
+ {
+ private DataRowView [] rows;
+ int on = -1;
+
+ internal DataViewEnumerator (DataRowView [] dataRowViews)
+ {
+ rows = dataRowViews;
+ }
+
+ public object Current {
+ get {
+ if (on == -1 || on >= rows.Length)
+ throw new InvalidOperationException ();
+ return rows [on];
+ }
+ }
+
+ public bool MoveNext ()
+ {
+ // TODO: how do you determine
+ // if a collection has been
+ // changed?
+ if (on < rows.Length - 1) {
+ on++;
+ return true;
+ }
+
+ return false; // EOF
+ }
+
+ public void Reset () {
+ on = -1;
+ }
+ }
+
+ private class RowComparer : IComparer
+ {
+ private SortableColumn [] sortColumns;
+ private DataTable table;
+ public RowComparer(DataTable table, SortableColumn[] sortColumns)
+ {
+ this.table = table;
+ this.sortColumns = sortColumns;
+ }
+
+ public SortableColumn[] SortedColumns {
+ get {
+ return sortColumns;
+ }
+ }
+
+ int IComparer.Compare (object x, object y)
+ {
+ if(x == null)
+ throw new Exception ("Object to compare is null: x");
+ if(y == null)
+ throw new Exception ("Object to compare is null: y");
+ DataRowView rowView = (DataRowView) y;
+ object [] keys = (object [])x;
+ for(int i = 0; i < sortColumns.Length; i++) {
+ SortableColumn sortColumn = sortColumns [i];
+ DataColumn dc = sortColumn.Column;
+
+ IComparable row = (IComparable) rowView.Row [dc];
+ object key = keys [i];
+
+ int result = CompareObjects (key,row);
+ if (result != 0) {
+ if (sortColumn.SortDirection == ListSortDirection.Ascending)
+ return result;
+ else
+ return -result;
+ }
+ }
+ return 0;
+ }
+
+ private int CompareObjects (object a, object b)
+ {
+ if (a == b)
+ return 0;
+ else if (a == null)
+ return -1;
+ else if (a == DBNull.Value)
+ return -1;
+ else if (b == null)
+ return 1;
+ else if (b == DBNull.Value)
+ return 1;
+
+ if((a is string) && (b is string)) {
+ a = ((string) a).ToUpper (table.Locale);
+ b = ((string) b).ToUpper (table.Locale);
+ }
+
+ if (a is IComparable)
+ return ((a as IComparable).CompareTo (b));
+ else if (b is IComparable)
+ return -((b as IComparable).CompareTo (a));
+
+ throw new ArgumentException ("Neither a nor b IComparable");
+ }
+ }
+
+ }
+}