PageRenderTime 53ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/class/System.Data/System.Data/DataView.cs

https://bitbucket.org/danipen/mono
C# | 1250 lines | 962 code | 185 blank | 103 comment | 236 complexity | 56c54cba09de2887baa41d3aa4ab2a54 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. //
  2. // System.Data.DataView.cs
  3. //
  4. // Author:
  5. // Daniel Morgan <danmorg@sc.rr.com>
  6. // Tim Coleman (tim@timcoleman.com)
  7. // Punit Todi (punits_mailbox@yahoo.com)
  8. // Atsushi Enomoto <atsushi@ximian.com>
  9. // Konstantin Triger (kostat@mainsoft.com)
  10. //
  11. // Copyright (C) Daniel Morgan, 2002, 2003
  12. // (C) Ximian, Inc 2002
  13. // Copyright (C) Tim Coleman, 2002-2003
  14. using System;
  15. using System.Collections;
  16. using System.ComponentModel;
  17. using System.Reflection;
  18. using System.Data.Common;
  19. using System.Globalization;
  20. using Mono.Data.SqlExpressions;
  21. using System.Text;
  22. namespace System.Data
  23. {
  24. /// <summary>
  25. /// A DataView is used in the binding of data between
  26. /// a DataTable and Windows Forms or Web Forms allowing
  27. /// a view of a DataTable for editing, filtering,
  28. /// navigation, searching, and sorting.
  29. /// </summary>
  30. //[Designer]
  31. [Editor ("Microsoft.VSDesigner.Data.Design.DataSourceEditor, " + Consts.AssemblyMicrosoft_VSDesigner,
  32. "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
  33. [DefaultEvent ("PositionChanged")]
  34. [DefaultProperty ("Table")]
  35. [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.DataViewDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")]
  36. public partial class DataView : MarshalByValueComponent, IEnumerable, ISupportInitialize {
  37. internal DataTable dataTable;
  38. string rowFilter = String.Empty;
  39. IExpression rowFilterExpr;
  40. string sort = String.Empty;
  41. ListSortDirection [] sortOrder;
  42. PropertyDescriptor sortProperty;
  43. DataColumn [] sortColumns;
  44. internal DataViewRowState rowState;
  45. internal DataRowView[] rowCache = new DataRowView [0];
  46. // BeginInit() support
  47. bool isInitPhase;
  48. bool inEndInit;
  49. DataTable initTable;
  50. bool initApplyDefaultSort;
  51. string initSort;
  52. string initRowFilter;
  53. DataViewRowState initRowState;
  54. // FIXME: what are the default values?
  55. bool allowNew = true;
  56. bool allowEdit = true;
  57. bool allowDelete = true;
  58. bool applyDefaultSort;
  59. //bool isSorted = false;
  60. bool isOpen;
  61. bool useDefaultSort = true;
  62. Index _index;
  63. internal DataRow _lastAdded;
  64. private DataViewManager dataViewManager;
  65. internal static ListChangedEventArgs ListResetEventArgs = new ListChangedEventArgs (ListChangedType.Reset,-1,-1);
  66. public DataView ()
  67. {
  68. rowState = DataViewRowState.CurrentRows;
  69. Open ();
  70. }
  71. public DataView (DataTable table)
  72. : this (table, (DataViewManager) null)
  73. {
  74. }
  75. internal DataView (DataTable table, DataViewManager manager)
  76. {
  77. dataTable = table;
  78. rowState = DataViewRowState.CurrentRows;
  79. dataViewManager = manager;
  80. Open ();
  81. }
  82. public DataView (DataTable table, string RowFilter,
  83. string Sort, DataViewRowState RowState)
  84. : this (table, null, RowFilter, Sort, RowState)
  85. {
  86. }
  87. internal DataView (DataTable table, DataViewManager manager,
  88. string RowFilter, string Sort, DataViewRowState RowState)
  89. {
  90. dataTable = table;
  91. dataViewManager = manager;
  92. rowState = DataViewRowState.CurrentRows;
  93. this.RowFilter = RowFilter;
  94. this.Sort = Sort;
  95. rowState = RowState;
  96. Open ();
  97. }
  98. [DataCategory ("Data")]
  99. #if !NET_2_0
  100. [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows deletes.")]
  101. #endif
  102. [DefaultValue (true)]
  103. public bool AllowDelete {
  104. get { return allowDelete; }
  105. set { allowDelete = value; }
  106. }
  107. [DataCategory ("Data")]
  108. #if !NET_2_0
  109. [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows edits.")]
  110. #endif
  111. [DefaultValue (true)]
  112. public bool AllowEdit {
  113. get { return allowEdit; }
  114. set { allowEdit = value; }
  115. }
  116. [DataCategory ("Data")]
  117. #if !NET_2_0
  118. [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows new rows to be added.")]
  119. #endif
  120. [DefaultValue (true)]
  121. public bool AllowNew {
  122. get { return allowNew; }
  123. set { allowNew = value; }
  124. }
  125. [DataCategory ("Data")]
  126. #if !NET_2_0
  127. [DataSysDescription ("Indicates whether to use the default sort if the Sort property is not set.")]
  128. #endif
  129. [DefaultValue (false)]
  130. [RefreshProperties (RefreshProperties.All)]
  131. public bool ApplyDefaultSort {
  132. get { return applyDefaultSort; }
  133. set {
  134. if (isInitPhase) {
  135. initApplyDefaultSort = value;
  136. return;
  137. }
  138. if (applyDefaultSort == value)
  139. return;
  140. applyDefaultSort = value;
  141. if (applyDefaultSort == true && (sort == null || sort == string.Empty))
  142. PopulateDefaultSort ();
  143. if (!inEndInit) {
  144. UpdateIndex (true);
  145. OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1));
  146. }
  147. }
  148. }
  149. // get the count of rows in the DataView after RowFilter
  150. // and RowStateFilter have been applied
  151. [Browsable (false)]
  152. #if !NET_2_0
  153. [DataSysDescription ("Returns the number of items currently in this view.")]
  154. #endif
  155. public int Count {
  156. get { return rowCache.Length; }
  157. }
  158. [Browsable (false)]
  159. #if !NET_2_0
  160. [DataSysDescription ("This returns a pointer to back to the DataViewManager that owns this DataSet (if any).")]
  161. #endif
  162. public DataViewManager DataViewManager {
  163. get { return dataViewManager; }
  164. }
  165. // Item indexer
  166. // the compiler creates a DefaultMemeberAttribute from
  167. // this IndexerNameAttribute
  168. [System.Runtime.CompilerServices.IndexerName("Item")]
  169. public DataRowView this [int recordIndex] {
  170. get {
  171. if (recordIndex > rowCache.Length)
  172. throw new IndexOutOfRangeException ("There is no row at position: " + recordIndex + ".");
  173. return rowCache [recordIndex];
  174. }
  175. }
  176. [DataCategory ("Data")]
  177. #if !NET_2_0
  178. [DataSysDescription ("Indicates an expression used to filter the data returned by this DataView.")]
  179. #endif
  180. [DefaultValue ("")]
  181. public virtual string RowFilter {
  182. get { return rowFilter; }
  183. set {
  184. if (value == null)
  185. value = String.Empty;
  186. if (isInitPhase) {
  187. initRowFilter = value;
  188. return;
  189. }
  190. CultureInfo info = (Table != null) ? Table.Locale : CultureInfo.CurrentCulture;
  191. if (String.Compare (rowFilter, value, false, info) == 0)
  192. return;
  193. if (value.Length == 0) {
  194. rowFilterExpr = null;
  195. } else {
  196. Parser parser = new Parser ();
  197. rowFilterExpr = parser.Compile (value);
  198. }
  199. rowFilter = value;
  200. if (!inEndInit) {
  201. UpdateIndex (true);
  202. OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1));
  203. }
  204. }
  205. }
  206. [DataCategory ("Data")]
  207. #if !NET_2_0
  208. [DataSysDescription ("Indicates the versions of data returned by this DataView.")]
  209. #endif
  210. [DefaultValue (DataViewRowState.CurrentRows)]
  211. public DataViewRowState RowStateFilter {
  212. get { return rowState; }
  213. set {
  214. if (isInitPhase) {
  215. initRowState = value;
  216. return;
  217. }
  218. if (value == rowState)
  219. return;
  220. rowState = value;
  221. if (!inEndInit) {
  222. UpdateIndex (true);
  223. OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1));
  224. }
  225. }
  226. }
  227. [DataCategory ("Data")]
  228. #if !NET_2_0
  229. [DataSysDescription ("Indicates the order in which data is returned by this DataView.")]
  230. #endif
  231. [DefaultValue ("")]
  232. public string Sort {
  233. get {
  234. if (useDefaultSort)
  235. return String.Empty;
  236. else
  237. return sort;
  238. }
  239. set {
  240. if (isInitPhase) {
  241. initSort = value;
  242. return;
  243. }
  244. if (value == Sort)
  245. return;
  246. if (value == null || value.Length == 0) {
  247. /* if given value is null useDefaultSort */
  248. useDefaultSort = true;
  249. /* if ApplyDefault sort is true try appling it */
  250. if (ApplyDefaultSort)
  251. PopulateDefaultSort ();
  252. } else {
  253. /* else donot useDefaultSort. set it as false */
  254. /* sort is set to value specified */
  255. useDefaultSort = false;
  256. sort = value;
  257. //sortedColumns = SortableColumn.ParseSortString (dataTable, value, true);
  258. }
  259. if (!inEndInit) {
  260. UpdateIndex (true);
  261. OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1));
  262. }
  263. }
  264. }
  265. [TypeConverter (typeof (DataTableTypeConverter))]
  266. [DataCategory ("Data")]
  267. #if !NET_2_0
  268. [DataSysDescription ("Indicates the table this DataView uses to get data.")]
  269. #endif
  270. [DefaultValue (null)]
  271. [RefreshProperties (RefreshProperties.All)]
  272. public DataTable Table {
  273. get { return dataTable; }
  274. set {
  275. if (value == dataTable)
  276. return;
  277. if (isInitPhase) {
  278. initTable = value;
  279. return;
  280. }
  281. if (value != null && value.TableName.Equals(string.Empty)) {
  282. throw new DataException("Cannot bind to DataTable with no name.");
  283. }
  284. if (dataTable != null)
  285. UnregisterEventHandlers ();
  286. dataTable = value;
  287. if (dataTable != null) {
  288. RegisterEventHandlers ();
  289. OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorChanged, 0, 0));
  290. sort = string.Empty;
  291. rowFilter = string.Empty;
  292. if (!inEndInit) {
  293. UpdateIndex (true);
  294. OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1));
  295. }
  296. }
  297. }
  298. }
  299. public virtual DataRowView AddNew ()
  300. {
  301. if (!IsOpen)
  302. throw new DataException ("DataView is not open.");
  303. if (!AllowNew)
  304. throw new DataException ("Cannot call AddNew on a DataView where AllowNew is false.");
  305. if (_lastAdded != null)
  306. // FIXME : finish last added
  307. CompleteLastAdded (true);
  308. _lastAdded = dataTable.NewRow ();
  309. UpdateIndex (true);
  310. OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, Count - 1, -1));
  311. return this [Count - 1];
  312. }
  313. internal void CompleteLastAdded (bool add)
  314. {
  315. DataRow dr = _lastAdded;
  316. if (add) {
  317. try {
  318. dataTable.Rows.Add (_lastAdded);
  319. //OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, Count - 1, -1));
  320. _lastAdded = null;
  321. UpdateIndex ();
  322. } catch (Exception) {
  323. _lastAdded = dr;
  324. throw;
  325. }
  326. } else {
  327. _lastAdded.CancelEdit ();
  328. _lastAdded = null;
  329. UpdateIndex ();
  330. OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, Count, -1));
  331. }
  332. }
  333. public void BeginInit ()
  334. {
  335. initTable = Table;
  336. initApplyDefaultSort = ApplyDefaultSort;
  337. initSort = Sort;
  338. initRowFilter = RowFilter;
  339. initRowState = RowStateFilter;
  340. isInitPhase = true;
  341. DataViewInitialized (false);
  342. }
  343. partial void DataViewInitialized (bool value);
  344. public void CopyTo (Array array, int index)
  345. {
  346. if (index + rowCache.Length > array.Length)
  347. throw new IndexOutOfRangeException ();
  348. int row = 0;
  349. for (; row < rowCache.Length && row < array.Length; row++)
  350. array.SetValue (rowCache [row], index + row);
  351. }
  352. public void Delete (int index)
  353. {
  354. if (!IsOpen)
  355. throw new DataException ("DataView is not open.");
  356. if (_lastAdded != null && index == Count) {
  357. CompleteLastAdded (false);
  358. return;
  359. }
  360. if (!AllowDelete)
  361. throw new DataException ("Cannot delete on a DataSource where AllowDelete is false.");
  362. if (index > rowCache.Length)
  363. throw new IndexOutOfRangeException ("There is no row at position: " + index + ".");
  364. DataRowView row = rowCache [index];
  365. row.Row.Delete ();
  366. }
  367. public void EndInit ()
  368. {
  369. isInitPhase = false;
  370. inEndInit = true;
  371. Table = initTable;
  372. ApplyDefaultSort = initApplyDefaultSort;
  373. Sort = initSort;
  374. RowFilter = initRowFilter;
  375. RowStateFilter = initRowState;
  376. inEndInit = false;
  377. UpdateIndex (true);
  378. DataViewInitialized (true);
  379. }
  380. public int Find (object key)
  381. {
  382. object [] keys = new object[] { key };
  383. return Find (keys);
  384. }
  385. public int Find (object [] key)
  386. {
  387. if (sort == null || sort.Length == 0)
  388. throw new ArgumentException ("Find finds a row based on a Sort order, and no Sort order is specified");
  389. if (Index == null)
  390. UpdateIndex (true);
  391. int index = -1;
  392. try {
  393. index = Index.FindIndex (key);
  394. } catch (FormatException) {
  395. // suppress exception
  396. } catch (InvalidCastException) {
  397. // suppress exception
  398. }
  399. return index;
  400. }
  401. public DataRowView [] FindRows (object key)
  402. {
  403. return FindRows (new object[] {key});
  404. }
  405. public DataRowView [] FindRows (object [] key)
  406. {
  407. if (sort == null || sort.Length == 0)
  408. throw new ArgumentException ("Find finds a row based on a Sort order, and no Sort order is specified");
  409. if (Index == null)
  410. UpdateIndex (true);
  411. int [] indexes = Index.FindAllIndexes (key);
  412. DataRowView[] rowViewArr = new DataRowView [indexes.Length];
  413. for (int r = 0; r < indexes.Length; r++)
  414. rowViewArr [r] = rowCache [indexes[r]];
  415. return rowViewArr;
  416. }
  417. public IEnumerator GetEnumerator ()
  418. {
  419. DataRowView[] dataRowViews = new DataRowView [Count];
  420. CopyTo (dataRowViews, 0);
  421. return dataRowViews.GetEnumerator ();
  422. }
  423. [DataCategory ("Data")]
  424. #if !NET_2_0
  425. [DataSysDescription ("Indicates that the data returned by this DataView has somehow changed.")]
  426. #endif
  427. public event ListChangedEventHandler ListChanged;
  428. [Browsable (false)]
  429. #if !NET_2_0
  430. [DataSysDescription ("Indicates whether the view is open. ")]
  431. #endif
  432. protected bool IsOpen {
  433. get { return isOpen; }
  434. }
  435. internal Index Index {
  436. get { return _index; }
  437. set {
  438. if (_index != null) {
  439. _index.RemoveRef ();
  440. Table.DropIndex (_index);
  441. }
  442. _index = value;
  443. if (_index != null)
  444. _index.AddRef ();
  445. }
  446. }
  447. protected void Close ()
  448. {
  449. if (dataTable != null)
  450. UnregisterEventHandlers ();
  451. Index = null;
  452. rowCache = new DataRowView [0];
  453. isOpen = false;
  454. }
  455. protected override void Dispose (bool disposing)
  456. {
  457. if (disposing)
  458. Close ();
  459. base.Dispose (disposing);
  460. }
  461. protected virtual void IndexListChanged (object sender, ListChangedEventArgs e)
  462. {
  463. }
  464. protected virtual void OnListChanged (ListChangedEventArgs e)
  465. {
  466. // Yes, under MS.NET, when it is overriden, the
  467. // events are not fired (even if it is essential
  468. // to internal processing).
  469. try {
  470. if (ListChanged != null)
  471. ListChanged (this, e);
  472. } catch {
  473. }
  474. }
  475. internal void ChangedList (ListChangedType listChangedType, int newIndex,int oldIndex)
  476. {
  477. ListChangedEventArgs e = new ListChangedEventArgs (listChangedType,newIndex,oldIndex);
  478. OnListChanged (e);
  479. }
  480. protected void Open ()
  481. {
  482. // I wonder if this comment is still valid, but keep
  483. // in the meantime.
  484. // FIXME: create the initial index cache to the DataTable, and
  485. // only refresh the index when the DataTable
  486. // has changes via column, row, or constraint
  487. // changed events. the index cache is generally
  488. // a DataViewRow array that points to the actual
  489. // DataRows in the this DataTable's DataRowCollection;
  490. // this index is really a cache that gets
  491. // created during Open(), gets Updated
  492. // when various properties of this view
  493. // changes, gets Updated when this DataTable's
  494. // row, column, or constraint collections have changed.
  495. // I'm not sure what else.
  496. // The data view will know one of the DataTable's
  497. // collections have changed via one of
  498. // its changed events.
  499. // Otherwise, if getting a/the DataRowView(s),
  500. // Count, or other properties, then just use the
  501. // index cache.
  502. // dataTable.ColumnChanged += new DataColumnChangeEventHandler(OnColumnChanged);
  503. UpdateIndex (true);
  504. if (dataTable != null)
  505. RegisterEventHandlers ();
  506. isOpen = true;
  507. }
  508. private void RegisterEventHandlers ()
  509. {
  510. //dataTable.ColumnChanging += new DataColumnChangeEventHandler(OnColumnChanging);
  511. dataTable.ColumnChanged += new DataColumnChangeEventHandler(OnColumnChanged);
  512. dataTable.RowChanged += new DataRowChangeEventHandler(OnRowChanged);
  513. //dataTable.RowDeleting += new DataRowChangeEventHandler(OnRowDeleting);
  514. dataTable.RowDeleted += new DataRowChangeEventHandler(OnRowDeleted);
  515. dataTable.Columns.CollectionChanged += new CollectionChangeEventHandler(ColumnCollectionChanged);
  516. dataTable.Columns.CollectionMetaDataChanged += new CollectionChangeEventHandler(ColumnCollectionChanged);
  517. dataTable.Constraints.CollectionChanged += new CollectionChangeEventHandler(OnConstraintCollectionChanged);
  518. dataTable.ChildRelations.CollectionChanged += new CollectionChangeEventHandler(OnRelationCollectionChanged);
  519. dataTable.ParentRelations.CollectionChanged += new CollectionChangeEventHandler(OnRelationCollectionChanged);
  520. dataTable.Rows.ListChanged += new ListChangedEventHandler (OnRowCollectionChanged);
  521. }
  522. private void OnRowCollectionChanged (object sender, ListChangedEventArgs args)
  523. {
  524. if (args.ListChangedType == ListChangedType.Reset) {
  525. rowCache = new DataRowView [0];
  526. UpdateIndex (true);
  527. OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1 ));
  528. }
  529. }
  530. private void UnregisterEventHandlers ()
  531. {
  532. // dataTable.ColumnChanging -= new DataColumnChangeEventHandler(OnColumnChanging);
  533. dataTable.ColumnChanged -= new DataColumnChangeEventHandler(OnColumnChanged);
  534. dataTable.RowChanged -= new DataRowChangeEventHandler(OnRowChanged);
  535. // dataTable.RowDeleting -= new DataRowChangeEventHandler(OnRowDeleting);
  536. dataTable.RowDeleted -= new DataRowChangeEventHandler(OnRowDeleted);
  537. dataTable.Columns.CollectionChanged -= new CollectionChangeEventHandler(ColumnCollectionChanged);
  538. dataTable.Columns.CollectionMetaDataChanged -= new CollectionChangeEventHandler(ColumnCollectionChanged);
  539. dataTable.Constraints.CollectionChanged -= new CollectionChangeEventHandler(OnConstraintCollectionChanged);
  540. dataTable.ChildRelations.CollectionChanged -= new CollectionChangeEventHandler(OnRelationCollectionChanged);
  541. dataTable.ParentRelations.CollectionChanged -= new CollectionChangeEventHandler(OnRelationCollectionChanged);
  542. dataTable.Rows.ListChanged -= new ListChangedEventHandler (OnRowCollectionChanged);
  543. }
  544. // These index storing and rowView preservation must be done
  545. // before the actual row value is changed; thus we can't use
  546. // RowChanging which accepts "already modified" DataRow.
  547. private void OnColumnChanged (object sender, DataColumnChangeEventArgs args)
  548. { /* not used */
  549. //UpdateIndex(true);
  550. }
  551. private void OnRowChanged (object sender, DataRowChangeEventArgs args)
  552. {
  553. int oldIndex,newIndex;
  554. oldIndex = newIndex = -1;
  555. oldIndex = IndexOf (args.Row);
  556. UpdateIndex (true);
  557. newIndex = IndexOf (args.Row);
  558. /* ItemAdded */
  559. if (args.Action == DataRowAction.Add && oldIndex != newIndex)
  560. OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, newIndex, -1));
  561. /* ItemChanged or ItemDeleted */
  562. if (args.Action == DataRowAction.Change) {
  563. if (oldIndex != -1 && oldIndex == newIndex)
  564. OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, newIndex, -1));
  565. else if (oldIndex != newIndex) {
  566. if (newIndex < 0)
  567. OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, newIndex, oldIndex));
  568. else
  569. OnListChanged (new ListChangedEventArgs (ListChangedType.ItemMoved, newIndex, oldIndex));
  570. }
  571. }
  572. /* Rollback - ItemAdded or ItemDeleted */
  573. if (args.Action == DataRowAction.Rollback) {
  574. if (oldIndex < 0 && newIndex > -1)
  575. OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, newIndex, -1));
  576. else if (oldIndex > -1 && newIndex < 0)
  577. OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, newIndex, oldIndex));
  578. else if (oldIndex != -1 && oldIndex == newIndex)
  579. OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, newIndex, -1));
  580. }
  581. }
  582. private void OnRowDeleted (object sender, DataRowChangeEventArgs args)
  583. {
  584. /* ItemDeleted */
  585. int newIndex, oldCount;
  586. oldCount = Count;
  587. newIndex = IndexOf (args.Row);
  588. UpdateIndex (true);
  589. /* Fire ListChanged only when the RowFilter is affected */
  590. if (oldCount != Count)
  591. OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, newIndex, -1));
  592. }
  593. protected virtual void ColumnCollectionChanged (object sender, CollectionChangeEventArgs e)
  594. {
  595. // UpdateIndex() is not invoked here (even if the sort
  596. // column is being removed).
  597. // PropertyDescriptor Add
  598. if (e.Action == CollectionChangeAction.Add)
  599. OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorAdded, 0, 0));
  600. // PropertyDescriptor Removed
  601. if (e.Action == CollectionChangeAction.Remove)
  602. OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorDeleted, 0, 0));
  603. // PropertyDescriptor Changed
  604. if (e.Action == CollectionChangeAction.Refresh)
  605. OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorChanged, 0, 0));
  606. }
  607. private void OnConstraintCollectionChanged (object sender, CollectionChangeEventArgs args)
  608. {
  609. // The Sort variable is set to the UniqueConstraint column.
  610. // if ApplyDefault Sort is true and Sort is null or is not set Explicitly
  611. // FIXME: The interal cache may change as result of change in Constraint collection
  612. // one such scenerio is taken care.
  613. // There may be more. I dont know what else can be done.
  614. /* useDefaultSort is set to false when Sort is set explicitly */
  615. if (args.Action == CollectionChangeAction.Add && args.Element is UniqueConstraint) {
  616. if (ApplyDefaultSort && useDefaultSort)
  617. PopulateDefaultSort ((UniqueConstraint) args.Element);
  618. }
  619. // UpdateIndex() is not invoked here.
  620. }
  621. private void OnRelationCollectionChanged (object sender, CollectionChangeEventArgs args)
  622. {
  623. /* PropertyDescriptor Add */
  624. if (args.Action == CollectionChangeAction.Add)
  625. OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorAdded,0,0));
  626. /* PropertyDescriptor Removed */
  627. if (args.Action == CollectionChangeAction.Remove)
  628. OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorDeleted,0,0));
  629. /* FIXME: PropertyDescriptor Changed ???*/
  630. if (args.Action == CollectionChangeAction.Refresh)
  631. OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorChanged,0,0));
  632. }
  633. // internal use by Mono
  634. protected void Reset ()
  635. {
  636. // TODO: what really happens?
  637. Close ();
  638. rowCache = new DataRowView [0];
  639. Open ();
  640. OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1 ));
  641. }
  642. protected void UpdateIndex ()
  643. {
  644. UpdateIndex (false);
  645. }
  646. // This is method is internal to
  647. // the Mono implementation of DataView; it
  648. // is not to be used from your code.
  649. //
  650. // Update the DataRowView array which is an index cache
  651. // into the DataTable's DataRowCollection.
  652. //
  653. // I assume this is what UpdateIndex is used for
  654. protected virtual void UpdateIndex (bool force)
  655. {
  656. if (Table == null)
  657. // FIXME
  658. return;
  659. if (Index == null || force) {
  660. sortColumns = DataTable.ParseSortString(Table, Sort, out sortOrder, false);
  661. Index = dataTable.GetIndex(sortColumns,sortOrder,RowStateFilter,FilterExpression,true);
  662. } else {
  663. Index.Key.RowStateFilter = RowStateFilter;
  664. Index.Reset();
  665. }
  666. int[] records = Index.GetAll ();
  667. if (records != null)
  668. InitDataRowViewArray (records,Index.Size);
  669. else
  670. rowCache = new DataRowView [0];
  671. }
  672. internal virtual IExpression FilterExpression {
  673. get { return rowFilterExpr; }
  674. }
  675. private void InitDataRowViewArray (int [] records, int size)
  676. {
  677. if (_lastAdded != null)
  678. rowCache = new DataRowView [size + 1];
  679. else
  680. rowCache = new DataRowView [size];
  681. for (int r = 0; r < size; r++)
  682. rowCache [r] = new DataRowView (this, Table.RecordCache [records [r]],r);
  683. if (_lastAdded != null)
  684. rowCache [size] = new DataRowView (this, _lastAdded, size);
  685. }
  686. PropertyDescriptorCollection ITypedList.GetItemProperties (PropertyDescriptor [] listAccessors)
  687. {
  688. if (dataTable == null)
  689. return new PropertyDescriptorCollection (new PropertyDescriptor [0]);
  690. // FIXME: use listAccessors somehow
  691. PropertyDescriptor [] descriptors =
  692. new PropertyDescriptor [dataTable.Columns.Count + dataTable.ChildRelations.Count];
  693. int d = 0;
  694. for (int col = 0; col < dataTable.Columns.Count; col ++) {
  695. DataColumn dataColumn = dataTable.Columns[col];
  696. DataColumnPropertyDescriptor descriptor;
  697. descriptor = new DataColumnPropertyDescriptor (dataColumn.ColumnName, col, null);
  698. descriptor.SetComponentType (typeof (System.Data.DataRowView));
  699. descriptor.SetPropertyType (dataColumn.DataType);
  700. descriptor.SetReadOnly (dataColumn.ReadOnly);
  701. descriptor.SetBrowsable (dataColumn.ColumnMapping != MappingType.Hidden);
  702. descriptors [d++] = descriptor;
  703. }
  704. for (int rel = 0; rel < dataTable.ChildRelations.Count; rel ++) {
  705. DataRelation dataRelation = dataTable.ChildRelations [rel];
  706. DataRelationPropertyDescriptor descriptor;
  707. descriptor = new DataRelationPropertyDescriptor (dataRelation);
  708. descriptors [d++] = descriptor;
  709. }
  710. return new PropertyDescriptorCollection (descriptors);
  711. }
  712. private int IndexOf (DataRow dr)
  713. {
  714. for (int i=0; i < rowCache.Length; i++)
  715. if (dr.Equals (rowCache [i].Row))
  716. return i;
  717. return -1;
  718. }
  719. private void PopulateDefaultSort ()
  720. {
  721. sort = string.Empty;
  722. foreach (Constraint c in dataTable.Constraints) {
  723. if (c is UniqueConstraint) {
  724. PopulateDefaultSort ((UniqueConstraint) c);
  725. break;
  726. }
  727. }
  728. }
  729. private void PopulateDefaultSort (UniqueConstraint uc)
  730. {
  731. if (isInitPhase)
  732. return;
  733. DataColumn [] columns = uc.Columns;
  734. if (columns.Length == 0) {
  735. sort = String.Empty;
  736. return;
  737. }
  738. StringBuilder builder = new StringBuilder ();
  739. builder.Append (columns[0].ColumnName);
  740. for (int i = 1; i < columns.Length; i++) {
  741. builder.Append (", ");
  742. builder.Append (columns [i].ColumnName);
  743. }
  744. sort = builder.ToString ();
  745. }
  746. internal DataView CreateChildView (DataRelation relation, int index)
  747. {
  748. if (relation == null || relation.ParentTable != Table)
  749. throw new ArgumentException("The relation is not parented to the table to which this DataView points.");
  750. int record = GetRecord (index);
  751. object[] keyValues = new object [relation.ParentColumns.Length];
  752. for (int i = 0; i < relation.ParentColumns.Length; i++)
  753. keyValues [i] = relation.ParentColumns [i] [record];
  754. return new RelatedDataView (relation.ChildColumns, keyValues);
  755. }
  756. private int GetRecord (int index)
  757. {
  758. if (index < 0 || index >= Count)
  759. throw new IndexOutOfRangeException(String.Format("There is no row at position {0}.", index));
  760. return (index == Index.Size) ?
  761. _lastAdded.IndexFromVersion (DataRowVersion.Default) :
  762. Index.IndexToRecord (index);
  763. }
  764. internal DataRowVersion GetRowVersion (int index)
  765. {
  766. int record = GetRecord (index);
  767. return Table.RecordCache [record].VersionFromIndex (record);
  768. }
  769. }
  770. partial class DataView : ITypedList {
  771. string ITypedList.GetListName (PropertyDescriptor [] listAccessors)
  772. {
  773. if (dataTable != null)
  774. return dataTable.TableName;
  775. return string.Empty;
  776. }
  777. }
  778. partial class DataView : ICollection {
  779. bool ICollection.IsSynchronized {
  780. get { return false; }
  781. }
  782. object ICollection.SyncRoot {
  783. get { return this; }
  784. }
  785. }
  786. partial class DataView : IList {
  787. bool IList.IsFixedSize {
  788. get { return false; }
  789. }
  790. bool IList.IsReadOnly {
  791. get { return false; }
  792. }
  793. object IList.this [int recordIndex] {
  794. get { return this [recordIndex]; }
  795. [MonoTODO]
  796. set { throw new InvalidOperationException (); }
  797. }
  798. int IList.Add (object value)
  799. {
  800. throw new ArgumentException ("Cannot add external objects to this list.");
  801. }
  802. void IList.Clear ()
  803. {
  804. throw new ArgumentException ("Cannot clear this list.");
  805. }
  806. bool IList.Contains (object value)
  807. {
  808. DataRowView drv = value as DataRowView;
  809. if (drv == null)
  810. return false;
  811. return drv.DataView == this;
  812. }
  813. int IList.IndexOf (object value)
  814. {
  815. DataRowView drv = value as DataRowView;
  816. if (drv != null && drv.DataView == this)
  817. return drv.Index;
  818. return -1;
  819. }
  820. void IList.Insert (int index,object value)
  821. {
  822. throw new ArgumentException ("Cannot insert external objects to this list.");
  823. }
  824. void IList.Remove (object value)
  825. {
  826. DataRowView drv = value as DataRowView;
  827. if (drv != null && drv.DataView == this)
  828. ((IList) this).RemoveAt (drv.Index);
  829. throw new ArgumentException ("Cannot remove external objects to this list.");
  830. }
  831. void IList.RemoveAt (int index)
  832. {
  833. Delete (index);
  834. }
  835. }
  836. partial class DataView : IBindingList {
  837. [MonoTODO]
  838. void IBindingList.AddIndex (PropertyDescriptor property)
  839. {
  840. throw new NotImplementedException ();
  841. }
  842. object IBindingList.AddNew ()
  843. {
  844. return this.AddNew ();
  845. }
  846. void IBindingList.ApplySort (PropertyDescriptor property, ListSortDirection direction)
  847. {
  848. if (!(property is DataColumnPropertyDescriptor))
  849. throw new ArgumentException ("Dataview accepts only DataColumnPropertyDescriptors", "property");
  850. sortProperty = property;
  851. string sort = String.Format ("[{0}]" , property.Name);
  852. if (direction == ListSortDirection.Descending)
  853. sort += " DESC";
  854. this.Sort = sort;
  855. }
  856. int IBindingList.Find (PropertyDescriptor property, object key)
  857. {
  858. DataColumn dc = Table.Columns [property.Name];
  859. Index index = Table.FindIndex (new DataColumn [] {dc}, sortOrder, RowStateFilter, FilterExpression);
  860. if (index == null)
  861. index = new Index (new Key (Table, new DataColumn [] {dc}, sortOrder, RowStateFilter, FilterExpression));
  862. return index.FindIndex (new object [] {key});
  863. }
  864. [MonoTODO]
  865. void IBindingList.RemoveIndex (PropertyDescriptor property)
  866. {
  867. throw new NotImplementedException ();
  868. }
  869. void IBindingList.RemoveSort ()
  870. {
  871. sortProperty = null;
  872. this.Sort = String.Empty;
  873. }
  874. bool IBindingList.AllowEdit {
  875. get { return AllowEdit; }
  876. }
  877. bool IBindingList.AllowNew {
  878. get { return AllowNew; }
  879. }
  880. bool IBindingList.AllowRemove {
  881. [MonoTODO]
  882. get { return AllowDelete; }
  883. }
  884. bool IBindingList.IsSorted {
  885. get { return (Sort != null && Sort.Length != 0); }
  886. }
  887. ListSortDirection IBindingList.SortDirection {
  888. get {
  889. if (sortOrder != null && sortOrder.Length > 0)
  890. return sortOrder [0];
  891. return ListSortDirection.Ascending;
  892. }
  893. }
  894. PropertyDescriptor IBindingList.SortProperty {
  895. get {
  896. if (sortProperty == null && sortColumns != null && sortColumns.Length > 0) {
  897. // return property from Sort String
  898. PropertyDescriptorCollection properties = ((ITypedList)this).GetItemProperties (null);
  899. return properties.Find (sortColumns [0].ColumnName, false);
  900. }
  901. return sortProperty;
  902. }
  903. }
  904. bool IBindingList.SupportsChangeNotification {
  905. get { return true; }
  906. }
  907. bool IBindingList.SupportsSearching {
  908. get { return true; }
  909. }
  910. bool IBindingList.SupportsSorting {
  911. get { return true; }
  912. }
  913. }
  914. #if NET_2_0
  915. partial class DataView : IBindingListView {
  916. string IBindingListView.Filter {
  917. get { return ((DataView) this).RowFilter; }
  918. set { ((DataView) this).RowFilter = value; }
  919. }
  920. ListSortDescriptionCollection IBindingListView.SortDescriptions {
  921. get {
  922. ListSortDescriptionCollection col = new ListSortDescriptionCollection ();
  923. for (int i = 0; i < sortColumns.Length; ++i) {
  924. ListSortDescription ldesc = new ListSortDescription (
  925. new DataColumnPropertyDescriptor (sortColumns [i]),
  926. sortOrder [i]);
  927. ((IList) col).Add (ldesc);
  928. }
  929. return col;
  930. }
  931. }
  932. bool IBindingListView.SupportsAdvancedSorting {
  933. get { return true; }
  934. }
  935. bool IBindingListView.SupportsFiltering {
  936. get { return true; }
  937. }
  938. [MonoTODO]
  939. void IBindingListView.ApplySort (ListSortDescriptionCollection sorts)
  940. {
  941. StringBuilder sb = new StringBuilder ();
  942. foreach (ListSortDescription ldesc in sorts)
  943. sb.AppendFormat ("[{0}]{1},", ldesc.PropertyDescriptor.Name,
  944. (ldesc.SortDirection == ListSortDirection.Descending ? " DESC" : string.Empty));
  945. this.Sort = sb.ToString (0, sb.Length-1);
  946. }
  947. void IBindingListView.RemoveFilter ()
  948. {
  949. ((IBindingListView) this).Filter = string.Empty;
  950. }
  951. }
  952. partial class DataView : ISupportInitializeNotification {
  953. private bool dataViewInitialized = true;
  954. [Browsable (false)]
  955. public bool IsInitialized {
  956. get { return dataViewInitialized; }
  957. }
  958. public event EventHandler Initialized;
  959. partial void DataViewInitialized (bool value)
  960. {
  961. dataViewInitialized = value;
  962. if (value)
  963. OnDataViewInitialized (new EventArgs ());
  964. }
  965. private void OnDataViewInitialized (EventArgs e)
  966. {
  967. if (null != Initialized)
  968. Initialized (this, e);
  969. }
  970. }
  971. partial class DataView {
  972. public virtual bool Equals (DataView view)
  973. {
  974. if (this == view)
  975. return true;
  976. if (!(this.Table == view.Table && this.Sort == view.Sort &&
  977. this.RowFilter == view.RowFilter &&
  978. this.RowStateFilter == view.RowStateFilter &&
  979. this.AllowEdit == view.AllowEdit &&
  980. this.AllowNew == view.AllowNew &&
  981. this.AllowDelete == view.AllowDelete &&
  982. this.Count == view.Count))
  983. return false;
  984. for (int i = 0; i < Count; ++i)
  985. if (!this [i].Equals (view [i]))
  986. return false;
  987. return true;
  988. }
  989. public DataTable ToTable ()
  990. {
  991. return this.ToTable (Table.TableName, false, new string[] {});
  992. }
  993. public DataTable ToTable (string tableName)
  994. {
  995. return this.ToTable (tableName, false, new string[] {});
  996. }
  997. public DataTable ToTable (bool distinct, params string[] columnNames)
  998. {
  999. return this.ToTable (Table.TableName, distinct, columnNames);
  1000. }
  1001. public DataTable ToTable (string tableName, bool distinct, params string[] columnNames)
  1002. {
  1003. if (columnNames == null)
  1004. throw new ArgumentNullException ("columnNames", "'columnNames' argument cannot be null.");
  1005. DataTable newTable = new DataTable (tableName);
  1006. DataColumn[] columns;
  1007. ListSortDirection[] sortDirection = null;
  1008. if (columnNames.Length > 0) {
  1009. columns = new DataColumn [columnNames.Length];
  1010. for (int i=0; i < columnNames.Length; ++i)
  1011. columns [i] = Table.Columns [columnNames [i]];
  1012. if (sortColumns != null) {
  1013. sortDirection = new ListSortDirection [columnNames.Length];
  1014. for (int i=0; i < columnNames.Length; ++i) {
  1015. sortDirection [i] = ListSortDirection.Ascending;
  1016. for (int j = 0; j < sortColumns.Length; ++j) {
  1017. if (sortColumns [j] != columns [i])
  1018. continue;
  1019. sortDirection [i] = sortOrder [j];
  1020. }
  1021. }
  1022. }
  1023. } else {
  1024. columns = (DataColumn[]) Table.Columns.ToArray (typeof (DataColumn));
  1025. sortDirection = sortOrder;
  1026. }
  1027. ArrayList expressionCols = new ArrayList ();
  1028. for (int i = 0; i < columns.Length; ++i) {
  1029. DataColumn col = columns [i].Clone ();
  1030. if (col.Expression != String.Empty) {
  1031. col.Expression = string.Empty;
  1032. expressionCols.Add (col);
  1033. }
  1034. if (col.ReadOnly)
  1035. col.ReadOnly = false;
  1036. newTable.Columns.Add (col);
  1037. }
  1038. DataRow [] rows;
  1039. // Get the index from index collection of the data table.
  1040. Index index = null;
  1041. if (sort != string.Empty)
  1042. index = Table.GetIndex(sortColumns,sortOrder,RowStateFilter,FilterExpression,true);
  1043. else
  1044. index = new Index (new Key(Table, columns, sortDirection, RowStateFilter, rowFilterExpr));
  1045. if (distinct)
  1046. rows = index.GetDistinctRows ();
  1047. else
  1048. rows = index.GetAllRows ();
  1049. foreach (DataRow row in rows) {
  1050. DataRow newRow = newTable.NewNotInitializedRow ();
  1051. newTable.Rows.AddInternal (newRow);
  1052. newRow.Original = -1;
  1053. if (row.HasVersion (DataRowVersion.Current))
  1054. newRow.Current = newTable.RecordCache.CopyRecord (Table, row.Current, -1);
  1055. else if (row.HasVersion (DataRowVersion.Original))
  1056. newRow.Current = newTable.RecordCache.CopyRecord (Table, row.Original, -1);
  1057. foreach (DataColumn col in expressionCols)
  1058. newRow [col] = row [col.ColumnName];
  1059. newRow.Original = -1;
  1060. }
  1061. return newTable;
  1062. }
  1063. }
  1064. #endif
  1065. }