2004-03-10 Umadevi S (sumadevi@novell.com)
[mono.git] / mcs / class / System.Data / System.Data / DataView.cs
1 //
2 // System.Data.DataView.cs
3 //
4 // Author:
5 //    Daniel Morgan <danmorg@sc.rr.com>
6 //    Tim Coleman (tim@timcoleman.com)
7 //
8 // Copyright (C) Daniel Morgan, 2002, 2003
9 // (C) Ximian, Inc 2002
10 // Copyright (C) Tim Coleman, 2002-2003
11 //
12
13 using System;
14 using System.Collections;
15 using System.ComponentModel;
16 using System.Reflection;
17
18 namespace System.Data 
19 {
20         /// <summary>
21         /// A DataView is used in the binding of data between
22         /// a DataTable and Windows Forms or Web Forms allowing
23         /// a view of a DataTable for editing, filtering,
24         /// navigation, searching, and sorting.
25         /// </summary>
26         //[Designer]
27         [Editor]
28         [DefaultEvent ("PositionChanged")]
29         [DefaultProperty ("Table")]
30         public class DataView : MarshalByValueComponent, IBindingList, IList, ICollection, IEnumerable, ITypedList, ISupportInitialize
31         {
32                 DataTable dataTable = null;
33                 string rowFilter = "";
34                 string sort = "";
35                 DataViewRowState rowState;
36                 DataRowView[] rowCache = null;
37                 
38                 // FIXME: what are the default values?
39                 bool allowNew = true; 
40                 bool allowEdit = true;
41                 bool allowDelete = true;
42                 bool applyDefaultSort = false;
43                 bool isSorted = false;
44
45                 bool isOpen = false;
46
47                 bool bInit = false;
48                 
49                 internal DataViewManager dataViewManager = null;
50
51                 public DataView () 
52                 {
53                         dataTable = new DataTable ();
54                         rowState = DataViewRowState.CurrentRows;
55                         Open ();
56                 }
57
58                 public DataView (DataTable table) 
59                 {
60                         dataTable = table;
61                         rowState = DataViewRowState.CurrentRows;
62                         Open ();
63                 }
64
65                 public DataView (DataTable table, string RowFilter,
66                                 string Sort, DataViewRowState RowState) 
67                 {
68                         dataTable = table;
69                         rowState = DataViewRowState.CurrentRows;
70                         rowFilter = RowFilter;
71                         sort = Sort;
72                         rowState = RowState;
73                         Open();
74                 }
75
76                 [DataCategory ("Data")]
77                 [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows deletes.")]
78                 [DefaultValue (true)]
79                 public bool AllowDelete {
80                         [MonoTODO]
81                         get {
82                                 return allowDelete;
83                         }
84                         
85                         [MonoTODO]
86                         set {
87                                 allowDelete = value;
88                         }
89                 }
90
91                 [DataCategory ("Data")]
92                 [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows edits.")]
93                 [DefaultValue (true)]
94                 public bool AllowEdit {
95                         [MonoTODO]
96                         get {
97                                 return allowEdit;
98                         }
99                         
100                         [MonoTODO]
101                         set {
102                                 allowEdit = value;
103                         }
104                 }
105
106                 [DataCategory ("Data")]
107                 [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows new rows to be added.")]
108                 [DefaultValue (true)]
109                 public bool AllowNew {
110                         [MonoTODO]
111                         get {
112                                 return allowNew;
113                         }
114                         
115                         [MonoTODO]
116                         set {
117                                 allowNew = value;
118                         }
119                 }
120
121                 [DataCategory ("Data")]
122                 [DataSysDescription ("Indicates whether to use the default sort if the Sort property is not set.")]
123                 [DefaultValue (false)]
124                 [RefreshProperties (RefreshProperties.All)]
125                 public bool ApplyDefaultSort {
126                         [MonoTODO]
127                         get {                           
128                                 return applyDefaultSort;
129                         }
130                         
131                         [MonoTODO]
132                         set {
133                                 applyDefaultSort = value;
134                                 // FIXME: update the index cache to the DataTable, and 
135                                 //        only refresh the index when the DataTable
136                                 //        has changes via column, row, or constraint
137                                 //        changed events
138                                 UpdateIndex ();
139                         }
140                 }
141
142                 // get the count of rows in the DataView after RowFilter 
143                 // and RowStateFilter have been applied
144                 [Browsable (false)]
145                 [DataSysDescription ("Returns the number of items currently in this view.")]
146                 public int Count {
147                         [MonoTODO]
148                         get {
149                                 // FIXME: remove this line once collection change
150                                 //        events from the DataTable are handled
151                                 UpdateIndex ();
152
153                                 return rowCache.Length;;
154                         }
155                 }
156
157                 [Browsable (false)]
158                 [DataSysDescription ("This returns a pointer to back to the DataViewManager that owns this DataSet (if any).")]
159                 public DataViewManager DataViewManager {
160                         [MonoTODO]
161                         get {
162                                 return dataViewManager;
163                         }
164                 }
165
166                 // Item indexer
167                 // the compiler creates a DefaultMemeberAttribute from
168                 // this IndexerNameAttribute
169                 [System.Runtime.CompilerServices.IndexerName("Item")]
170                 public DataRowView this[int recordIndex] {
171                         [MonoTODO]
172                         get {
173                                 // FIXME: use index cache to the DataTable, and 
174                                 //        only refresh the index when the DataTable
175                                 //        has changes via column, row, or constraint
176                                 //        changed events
177                                 // Remove this line once changed events are handled
178                                 UpdateIndex ();
179                                 
180                                 return rowCache[recordIndex];
181                         }
182                 }
183
184                 [DataCategory ("Data")]
185                 [DataSysDescription ("Indicates an expression used to filter the data returned by this DataView.")]
186                 [DefaultValue ("")]
187                 public virtual string RowFilter {
188                         [MonoTODO]
189                         get {
190                                 return rowFilter;
191                         }
192                         
193                         [MonoTODO]
194                         set {
195                                 rowFilter = value;
196                                 // FIXME: update the index cache to the DataTable, and 
197                                 //        only refresh the index when the DataTable
198                                 //        has changes via column, row, or constraint
199                                 //        changed events
200                                 UpdateIndex ();
201                         }
202                 }
203
204                 [DataCategory ("Data")]
205                 [DataSysDescription ("Indicates the versions of data returned by this DataView.")]
206                 [DefaultValue (DataViewRowState.CurrentRows)]
207                 public DataViewRowState RowStateFilter {
208                         [MonoTODO]
209                         get {
210                                 return rowState;
211                         }
212                         
213                         [MonoTODO]
214                         set {
215                                 rowState = value;
216                                 // FIXME: update the index cache to the DataTable, and 
217                                 //        only refresh the index when the DataTable
218                                 //        has changes via column, row, or constraint
219                                 //        changed events
220                                 UpdateIndex ();
221                         }
222                 }
223
224                 [DataCategory ("Data")]
225                 [DataSysDescription ("Indicates the order in which data is returned by this DataView.")]
226                 [DefaultValue ("")]
227                 public string Sort {
228                         [MonoTODO]
229                         get {
230                                 return sort;
231                         }
232                         
233                         [MonoTODO]
234                         set {
235                                 sort = value;
236                                 // FIXME: update the index cache to the DataTable, and 
237                                 //        only refresh the index when the DataTable
238                                 //        has changes via column, row, or constraint
239                                 //        changed events
240                                 UpdateIndex ();
241                         }
242                 }
243
244                 [DataCategory ("Data")]
245                 [DataSysDescription ("Indicates the table this DataView uses to get data.")]
246                 [DefaultValue (null)]
247                 [RefreshProperties (RefreshProperties.All)]
248                 public DataTable Table {
249                         [MonoTODO]
250                         get {
251                                 return dataTable;
252                         }
253                         
254                         [MonoTODO]
255                         set {
256                                 dataTable = value;
257                                 // FIXME: update the index cache to the DataTable, and 
258                                 //        only refresh the index when the DataTable
259                                 //        has changes via column, row, or constraint
260                                 //        changed events
261                                 UpdateIndex ();
262                         }
263                 }
264
265                 [MonoTODO]
266                 public virtual DataRowView AddNew() 
267                 {
268                         if (!IsOpen)
269                                 throw new DataException ("DataView is not open.");
270                         if (!AllowNew)
271                                 throw new DataException ("Cannot call AddNew on a DataView where AllowNew is false.");
272                         
273                         DataRow row = dataTable.NewRow ();
274                         DataRowView view = new DataRowView (this, row);
275                         
276                         dataTable.Rows.Add (row);
277
278                         UpdateIndex ();
279                         OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, rowCache.Length));
280                         return view;
281                 }
282
283                 [MonoTODO]
284                 public void BeginInit() 
285                 {
286                         bInit = true; 
287                         // FIXME:
288                 }
289
290                 [MonoTODO]
291                 public void CopyTo (Array array, int index) 
292                 {
293                         // FIXME: use index cache to the DataTable, and 
294                         //        only refresh the index when the DataTable
295                         //        has changes via column, row, or constraint
296                         //        changed events
297                         UpdateIndex ();
298                         
299                         int row = 0;
300                         for (; row < rowCache.Length && row < array.Length; row++) {
301                                 array.SetValue (rowCache[row], index + row);
302                         }
303                         if (row < array.Length) {
304                                 for (int r = 0; r < array.Length; r++) {
305                                         array.SetValue (null, index + r);
306                                 }
307                         }
308                 }
309
310                 public void Delete(int index) 
311                 {
312                         if (!IsOpen)
313                                 throw new DataException ("DataView is not open.");
314                         if (!AllowDelete)
315                                 throw new DataException ("Cannot delete on a DataSource where AllowDelete is false.");
316                         
317                         UpdateIndex ();
318
319                         if (index > rowCache.Length)
320                                 throw new IndexOutOfRangeException ("There is no row at " +
321                                                 "position: " + index + ".");
322                         
323                         DataRowView row = rowCache [index];
324                         row.Row.Delete ();
325
326                         OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, index));
327                 }
328
329 #if NET_1_2
330                 [MonoTODO]
331                 public virtual bool Equals (DataView dv)
332                 {
333                         throw new NotImplementedException ();
334                 }
335 #endif
336
337                 [MonoTODO]
338                 public void EndInit() 
339                 {
340                         bInit = false;
341                         // FIXME:
342                 }
343
344                 [MonoTODO]
345                 public int Find(object key) 
346                 {
347                         // FIXME: use index cache to the DataTable, and 
348                         //        only refresh the index when the DataTable
349                         //        has changes via column, row, or constraint
350                         //        changed events
351
352                         throw new NotImplementedException ();
353                 }
354
355                 [MonoTODO]
356                 public int Find(object[] key) 
357                 {
358                         // FIXME: use an index cache to the DataTable, and 
359                         //        only refresh the index when the DataTable
360                         //        has changes via column, row, or constraint
361                         //        changed events
362
363                         throw new NotImplementedException ();
364                 }
365
366                 [MonoTODO]
367                 public DataRowView[] FindRows(object key) 
368                 {
369                         // FIXME: use an index cache to the DataTable, and 
370                         //        only refresh the index when the DataTable
371                         //        has changes via column, row, or constraint
372                         //        changed events
373
374                         throw new NotImplementedException ();
375                 }
376
377                 [MonoTODO]
378                 public DataRowView[] FindRows(object[] key) 
379                 {
380                         // FIXME: use an index cache to the DataTable, and 
381                         //        only refresh the index when the DataTable
382                         //        has changes via column, row, or constraint
383                         //        changed events
384                         
385                         throw new NotImplementedException ();
386                 }
387
388                 [MonoTODO]
389                 public IEnumerator GetEnumerator() 
390                 {
391                         // FIXME: use an index cache to the DataTable, and 
392                         //        only refresh the index when the DataTable
393                         //        has changes via column, row, or constraint
394                         //        changed events
395                         UpdateIndex ();                                 
396
397                         return new DataViewEnumerator (rowCache);
398                 }
399                 
400                 [MonoTODO]
401                 [DataCategory ("Data")]
402                 [DataSysDescription ("Indicates the data returned by this DataView has somehow changed.")]
403                 public event ListChangedEventHandler ListChanged;
404
405                 protected bool IsOpen {
406                         [MonoTODO]
407                         get {
408                                 return isOpen;
409                         }
410                 }
411
412                 [MonoTODO]
413                 protected void Close() 
414                 {
415                         // FIXME:
416                         isOpen = false;
417                 }
418
419                 [MonoTODO]
420                 protected virtual void ColumnCollectionChanged (object sender, 
421                                                         CollectionChangeEventArgs e) 
422                 {
423                         throw new NotImplementedException ();
424                 }
425
426                 protected override void Dispose (bool disposing) 
427                 {
428                         if (disposing)
429                                 Close ();
430
431                         base.Dispose (disposing);
432                 }
433
434                 [MonoTODO]
435                 protected virtual void IndexListChanged(object sender, ListChangedEventArgs e) 
436                 {
437                         throw new NotImplementedException ();
438                 }
439
440                 [MonoTODO]
441                 protected virtual void OnListChanged(ListChangedEventArgs e) 
442                 {
443                         try {
444                                 if (ListChanged != null)
445                                         ListChanged (this, e);
446                         } catch {
447                         }
448                 }
449
450                 [MonoTODO]
451                 protected void Open() 
452                 {
453                         // FIXME: create the initial index cache to the DataTable, and 
454                         //        only refresh the index when the DataTable
455                         //        has changes via column, row, or constraint
456                         //        changed events. the index cache is generally
457                         //        a DataViewRow array that points to the actual
458                         //        DataRows in the this DataTable's DataRowCollection;
459                         //        this index is really a cache that gets 
460                         //        created during Open(), gets Updated 
461                         //        when various properties of this view
462                         //        changes, gets Updated when this DataTable's 
463                         //        row, column, or constraint collections have changed.
464                         //        I'm not sure what else.
465                         //        The data view will know one of the DataTable's
466                         //        collections have changed via one of 
467                         //        its changed events.
468                         //        Otherwise, if getting a/the DataRowView(s),
469                         //        Count, or other properties, then just use the
470                         //        index cache.
471                         UpdateIndex (true);
472                         isOpen = true;
473                 }
474
475                 // internal use by Mono
476                 protected void Reset() \r
477                 {\r
478                         // TODO: what really happens?\r
479                         Close ();\r
480                         rowCache = null;\r
481                         Open ();\r
482                         OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1));
483                 }\r
484
485 #if NET_1_2
486                 [MonoTODO]
487                 public DataTable ToTable ()
488                 {
489                         throw new NotImplementedException ();
490                 }
491
492                 [MonoTODO]
493                 public DataTable ToTable (bool isDistinct, string[] columnNames)
494                 {
495                         throw new NotImplementedException ();
496                 }
497 #endif
498
499                 // internal use by Mono
500                 protected virtual void UpdateIndex () \r
501                 {\r
502                         UpdateIndex (false);\r
503                 }\r
504
505                 // This is method is internal to 
506                 // the Mono implementation of DataView; it
507                 // is not to be used from your code.
508                 //
509                 // Update the DataRowView array which is an index cache
510                 // into the DataTable's DataRowCollection.
511                 //
512                 // I assume this is what UpdateIndex is used for
513                 protected virtual void UpdateIndex(bool force) 
514                 {
515                         DataRowView[] newRowCache = null;
516                         DataRow[] rows = null;
517                         
518                         rows = dataTable.Select (RowFilter, Sort, RowStateFilter);
519
520                         newRowCache = new DataRowView[rows.Length];
521                         for (int r = 0; r < rows.Length; r++) {
522                                 newRowCache[r] = new DataRowView (this, rows[r]);
523                         }
524                         rowCache = newRowCache;
525                 }
526
527                 [MonoTODO]
528                 PropertyDescriptorCollection ITypedList.GetItemProperties (PropertyDescriptor[] listAccessors) 
529                 {
530                         // FIXME: use listAccessors somehow
531
532                         DataColumnPropertyDescriptor[] descriptors = 
533                                 new DataColumnPropertyDescriptor[dataTable.Columns.Count];
534
535                         DataColumnPropertyDescriptor descriptor;
536                         DataColumn dataColumn;
537                         for (int col = 0; col < dataTable.Columns.Count; col ++)
538                         {
539                                 dataColumn = dataTable.Columns[col];
540                                 
541                                 descriptor = new DataColumnPropertyDescriptor(
542                                         dataColumn.ColumnName, col, null);
543                                 descriptor.SetComponentType (typeof (System.Data.DataRowView));
544                                 descriptor.SetPropertyType (dataColumn.DataType);
545                                 descriptor.SetReadOnly (dataColumn.ReadOnly);
546
547                                 descriptors[col] = descriptor;
548                         }
549
550                         return new PropertyDescriptorCollection (descriptors);
551                 }
552
553                 [MonoTODO]
554                 string ITypedList.GetListName (PropertyDescriptor[] listAccessors) 
555                 {
556                         return "";
557                 }
558
559                 //int ICollection.Count { 
560                 //      get {
561                 //              return Count;
562                 //      } 
563                 //}
564
565                 bool ICollection.IsSynchronized { 
566                         [MonoTODO]
567                         get {
568                                 return false;
569                         } 
570                 }
571
572                 object ICollection.SyncRoot { 
573                         [MonoTODO]
574                         get {
575                                 // FIXME:
576                                 return this;
577                         }
578                 }
579
580                 //void ICollection.CopyTo (Array array, int index) 
581                 //{
582                 //      CopyTo (array, index);
583                 //}
584
585                 bool IList.IsFixedSize {
586                         [MonoTODO]
587                         get {
588                                 return false;
589                         }
590                 }
591                 
592                 bool IList.IsReadOnly {
593                         [MonoTODO]
594                         get {
595                                 return false;
596                         }
597                 }
598
599                 object IList.this[int recordIndex] {
600                         [MonoTODO]
601                         get {
602                                 return this[recordIndex];
603                         }
604
605                         [MonoTODO]
606                         set{
607                                 throw new InvalidOperationException();
608                         }\r
609                 }
610
611                 [MonoTODO]
612                 int IList.Add (object value) 
613                 {
614                         throw new NotImplementedException ();
615                 }
616
617                 [MonoTODO]
618                 void IList.Clear () 
619                 {
620                         throw new NotImplementedException ();
621                 }
622
623                 [MonoTODO]
624                 bool IList.Contains (object value) 
625                 {
626                         throw new NotImplementedException ();
627                 }
628
629                 [MonoTODO]
630                 int IList.IndexOf (object value) 
631                 {
632                         throw new NotImplementedException ();
633                 }
634                         
635                 [MonoTODO]
636                 void IList.Insert(int index,object value) 
637                 {
638                         throw new NotImplementedException ();
639                 }
640
641                 [MonoTODO]
642                 void IList.Remove(object value) 
643                 {
644                         throw new NotImplementedException ();
645                 }
646
647                 [MonoTODO]
648                 void IList.RemoveAt(int index) 
649                 {
650                         throw new NotImplementedException ();
651                 }
652
653                 #region IBindingList implementation
654
655                 [MonoTODO]
656                 void IBindingList.AddIndex (PropertyDescriptor property) 
657                 {
658                         throw new NotImplementedException ();
659                 }
660
661                 [MonoTODO]
662                 object IBindingList.AddNew () 
663                 {
664                         throw new NotImplementedException ();
665                 }
666
667                 [MonoTODO]
668                 void IBindingList.ApplySort (PropertyDescriptor property, ListSortDirection direction) 
669                 {
670                         throw new NotImplementedException ();
671                 }
672
673                 [MonoTODO]
674                 int IBindingList.Find (PropertyDescriptor property, object key) 
675                 {
676                         throw new NotImplementedException ();
677                 }
678
679                 [MonoTODO]
680                 void IBindingList.RemoveIndex (PropertyDescriptor property) 
681                 {
682                         throw new NotImplementedException ();
683                 }
684
685                 [MonoTODO]
686                 void IBindingList.RemoveSort () 
687                 {
688                         throw new NotImplementedException ();
689                 }
690                 
691                 bool IBindingList.AllowEdit {
692                         [MonoTODO]
693                         get {
694                                 return AllowEdit;
695                         }
696                 }
697
698                 bool IBindingList.AllowNew {
699                         [MonoTODO]
700                         get {
701                                 return AllowNew;
702                         }
703                 }
704
705                 bool IBindingList.AllowRemove {
706                         [MonoTODO]
707                         get {
708                                 return AllowDelete;
709                         }
710                 }
711
712                 bool IBindingList.IsSorted {
713                         [MonoTODO]
714                         get {
715                                 return isSorted;
716                         }
717                 }
718
719                 ListSortDirection IBindingList.SortDirection {
720                         [MonoTODO]
721                         get {
722                                 // FIXME: 
723                                 return ListSortDirection.Ascending;
724                         }
725                 }
726
727                 PropertyDescriptor IBindingList.SortProperty {
728                         [MonoTODO]
729                         get {
730                                 // FIXME:
731                                 return null;
732                         }
733                 }
734
735                 bool IBindingList.SupportsChangeNotification {
736                         [MonoTODO]
737                         get {
738                                 return false;
739                         }
740                 }
741
742                 bool IBindingList.SupportsSearching {
743                         [MonoTODO]
744                         get {
745                                 return false;
746                         }
747                 }
748
749                 bool IBindingList.SupportsSorting {
750                         [MonoTODO]
751                         get {
752                                 return false;
753                         }
754                 }
755
756                 #endregion // IBindingList implementation
757
758                 private class DataViewEnumerator : IEnumerator 
759                 {
760                         private DataRowView[] rows;
761                         int on = -1;
762
763                         internal DataViewEnumerator (DataRowView[] dataRowViews) 
764                         {
765                                 rows = dataRowViews;
766                         }
767
768                         public object Current {
769                                 get {
770                                         if (on == -1 || on >= rows.Length)
771                                                 throw new InvalidOperationException ();
772                                         return rows[on];
773                                 }
774                         }
775
776                         public bool MoveNext () 
777                         {
778                                 // TODO: how do you determine
779                                 // if a collection has been
780                                 // changed?
781                                 if (on < rows.Length - 1) {
782                                         on++;
783                                         return true;
784                                 }
785
786                                 return false; // EOF
787                         }
788
789                         public void Reset () {
790                                 on = -1;
791                         }
792                 }
793         }
794 }
795