2003-03-27 Ville Palo <vi64pa@kolumbus.fi>
[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
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.None;
55                         Open ();
56                 }
57
58                 public DataView (DataTable table) 
59                 {
60                         dataTable = table;
61                         rowState = DataViewRowState.None;
62                         Open ();
63                 }
64
65                 public DataView (DataTable table, string RowFilter,
66                                 string Sort, DataViewRowState RowState) 
67                 {
68                         dataTable = table;
69                         rowState = DataViewRowState.None;
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                         throw new NotImplementedException ();
269                 }
270
271                 [MonoTODO]
272                 public void BeginInit() 
273                 {
274                         bInit = true; 
275                         // FIXME:
276                 }
277
278                 [MonoTODO]
279                 public void CopyTo (Array array, int index) 
280                 {
281                         // FIXME: use index cache to the DataTable, and 
282                         //        only refresh the index when the DataTable
283                         //        has changes via column, row, or constraint
284                         //        changed events
285                         UpdateIndex ();
286                         
287                         int row = 0;
288                         for (; row < rowCache.Length && row < array.Length; row++) {
289                                 array.SetValue (rowCache[row], index + row);
290                         }
291                         if (row < array.Length) {
292                                 for (int r = 0; r < array.Length; r++) {
293                                         array.SetValue (null, index + r);
294                                 }
295                         }
296                 }
297
298                 [MonoTODO]
299                 public void Delete(int index) 
300                 {
301                         throw new NotImplementedException ();
302                 }
303
304                 [MonoTODO]
305                 public void EndInit() 
306                 {
307                         bInit = false;
308                         // FIXME:
309                 }
310
311                 [MonoTODO]
312                 public int Find(object key) 
313                 {
314                         // FIXME: use index cache to the DataTable, and 
315                         //        only refresh the index when the DataTable
316                         //        has changes via column, row, or constraint
317                         //        changed events
318
319                         throw new NotImplementedException ();
320                 }
321
322                 [MonoTODO]
323                 public int Find(object[] key) 
324                 {
325                         // FIXME: use an index cache to the DataTable, and 
326                         //        only refresh the index when the DataTable
327                         //        has changes via column, row, or constraint
328                         //        changed events
329
330                         throw new NotImplementedException ();
331                 }
332
333                 [MonoTODO]
334                 public DataRowView[] FindRows(object key) 
335                 {
336                         // FIXME: use an index cache to the DataTable, and 
337                         //        only refresh the index when the DataTable
338                         //        has changes via column, row, or constraint
339                         //        changed events
340
341                         throw new NotImplementedException ();
342                 }
343
344                 [MonoTODO]
345                 public DataRowView[] FindRows(object[] key) 
346                 {
347                         // FIXME: use an 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 IEnumerator GetEnumerator() 
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                         UpdateIndex ();                                 
363
364                         return new DataViewEnumerator (rowCache);
365                 }
366                 
367                 [MonoTODO]
368                 [DataCategory ("Data")]
369                 [DataSysDescription ("Indicates the data returned by this DataView has somehow changed.")]
370                 public event ListChangedEventHandler ListChanged;
371
372                 protected bool IsOpen {
373                         [MonoTODO]
374                         get {
375                                 return isOpen;
376                         }
377                 }
378
379                 [MonoTODO]
380                 protected void Close() 
381                 {
382                         // FIXME:
383                         isOpen = false;
384                 }
385
386                 [MonoTODO]
387                 protected virtual void ColumnCollectionChanged (object sender, 
388                                                         CollectionChangeEventArgs e) 
389                 {
390                         throw new NotImplementedException ();
391                 }
392
393                 protected override void Dispose (bool disposing) 
394                 {
395                         if (disposing)
396                                 Close ();
397
398                         base.Dispose (disposing);
399                 }
400
401                 [MonoTODO]
402                 protected virtual void IndexListChanged(object sender, ListChangedEventArgs e) 
403                 {
404                         throw new NotImplementedException ();
405                 }
406
407                 [MonoTODO]
408                 protected virtual void OnListChanged(ListChangedEventArgs e) 
409                 {
410                         throw new NotImplementedException ();
411                 }
412
413                 [MonoTODO]
414                 protected void Open() 
415                 {
416                         // FIXME: create the initial index cache to the DataTable, and 
417                         //        only refresh the index when the DataTable
418                         //        has changes via column, row, or constraint
419                         //        changed events. the index cache is generally
420                         //        a DataViewRow array that points to the actual
421                         //        DataRows in the this DataTable's DataRowCollection;
422                         //        this index is really a cache that gets 
423                         //        created during Open(), gets Updated 
424                         //        when various properties of this view
425                         //        changes, gets Updated when this DataTable's 
426                         //        row, column, or constraint collections have changed.
427                         //        I'm not sure what else.
428                         //        The data view will know one of the DataTable's
429                         //        collections have changed via one of 
430                         //        its changed events.
431                         //        Otherwise, if getting a/the DataRowView(s),
432                         //        Count, or other properties, then just use the
433                         //        index cache.
434                         UpdateIndex (true);
435                         isOpen = true;
436                 }
437
438                 // internal use by Mono
439                 protected void Reset() \r
440                 {\r
441                         // TODO: what really happens?\r
442                         Close ();\r
443                         rowCache = null;\r
444                         Open ();\r
445                 }\r
446
447                 // internal use by Mono
448                 protected virtual void UpdateIndex () \r
449                 {\r
450                         UpdateIndex (false);\r
451                 }\r
452
453                 // This is method is internal to 
454                 // the Mono implementation of DataView; it
455                 // is not to be used from your code.
456                 //
457                 // Update the DataRowView array which is an index cache
458                 // into the DataTable's DataRowCollection.
459                 //
460                 // I assume this is what UpdateIndex is used for
461                 protected virtual void UpdateIndex(bool force) 
462                 {
463                         DataRowView[] newRowCache = null;
464                         DataRow[] rows = null;
465                         
466                         rows = dataTable.Select (RowFilter, Sort, RowStateFilter);
467
468                         newRowCache = new DataRowView[rows.Length];
469                         for (int r = 0; r < rows.Length; r++) {
470                                 newRowCache[r] = new DataRowView (this, rows[r]);
471                         }
472                         rowCache = newRowCache;
473                 }
474
475                 [MonoTODO]
476                 PropertyDescriptorCollection ITypedList.GetItemProperties (PropertyDescriptor[] listAccessors) 
477                 {
478                         // FIXME: use listAccessors somehow
479
480                         DataColumnPropertyDescriptor[] descriptors = 
481                                 new DataColumnPropertyDescriptor[dataTable.Columns.Count];
482
483                         DataColumnPropertyDescriptor descriptor;
484                         DataColumn dataColumn;
485                         for (int col = 0; col < dataTable.Columns.Count; col ++)
486                         {
487                                 dataColumn = dataTable.Columns[col];
488                                 
489                                 descriptor = new DataColumnPropertyDescriptor(
490                                         dataColumn.ColumnName, col, null);
491                                 descriptor.SetComponentType (typeof (System.Data.DataRowView));
492                                 descriptor.SetPropertyType (dataColumn.DataType);
493                                 
494                                 descriptors[col] = descriptor;
495                         }
496
497                         return new PropertyDescriptorCollection (descriptors);
498                 }
499
500                 [MonoTODO]
501                 string ITypedList.GetListName (PropertyDescriptor[] listAccessors) 
502                 {
503                         return "";
504                 }
505
506                 //int ICollection.Count { 
507                 //      get {
508                 //              return Count;
509                 //      } 
510                 //}
511
512                 bool ICollection.IsSynchronized { 
513                         [MonoTODO]
514                         get {
515                                 return false;
516                         } 
517                 }
518
519                 object ICollection.SyncRoot { 
520                         [MonoTODO]
521                         get {
522                                 // FIXME:
523                                 return this;
524                         }
525                 }
526
527                 //void ICollection.CopyTo (Array array, int index) 
528                 //{
529                 //      CopyTo (array, index);
530                 //}
531
532                 bool IList.IsFixedSize {
533                         [MonoTODO]
534                         get {
535                                 return false;
536                         }
537                 }
538                 
539                 bool IList.IsReadOnly {
540                         [MonoTODO]
541                         get {
542                                 return false;
543                         }
544                 }
545
546                 object IList.this[int recordIndex] {
547                         [MonoTODO]
548                         get {
549                                 return this[recordIndex];
550                         }
551
552                         [MonoTODO]
553                         set{
554                                 throw new InvalidOperationException();
555                         }\r
556                 }
557
558                 [MonoTODO]
559                 int IList.Add (object value) 
560                 {
561                         throw new NotImplementedException ();
562                 }
563
564                 [MonoTODO]
565                 void IList.Clear () 
566                 {
567                         throw new NotImplementedException ();
568                 }
569
570                 [MonoTODO]
571                 bool IList.Contains (object value) 
572                 {
573                         throw new NotImplementedException ();
574                 }
575
576                 [MonoTODO]
577                 int IList.IndexOf (object value) 
578                 {
579                         throw new NotImplementedException ();
580                 }
581                         
582                 [MonoTODO]
583                 void IList.Insert(int index,object value) 
584                 {
585                         throw new NotImplementedException ();
586                 }
587
588                 [MonoTODO]
589                 void IList.Remove(object value) 
590                 {
591                         throw new NotImplementedException ();
592                 }
593
594                 [MonoTODO]
595                 void IList.RemoveAt(int index) 
596                 {
597                         throw new NotImplementedException ();
598                 }
599
600                 #region IBindingList implementation
601
602                 [MonoTODO]
603                 void IBindingList.AddIndex (PropertyDescriptor property) 
604                 {
605                         throw new NotImplementedException ();
606                 }
607
608                 [MonoTODO]
609                 object IBindingList.AddNew () 
610                 {
611                         throw new NotImplementedException ();
612                 }
613
614                 [MonoTODO]
615                 void IBindingList.ApplySort (PropertyDescriptor property, ListSortDirection direction) 
616                 {
617                         throw new NotImplementedException ();
618                 }
619
620                 [MonoTODO]
621                 int IBindingList.Find (PropertyDescriptor property, object key) 
622                 {
623                         throw new NotImplementedException ();
624                 }
625
626                 [MonoTODO]
627                 void IBindingList.RemoveIndex (PropertyDescriptor property) 
628                 {
629                         throw new NotImplementedException ();
630                 }
631
632                 [MonoTODO]
633                 void IBindingList.RemoveSort () 
634                 {
635                         throw new NotImplementedException ();
636                 }
637                 
638                 bool IBindingList.AllowEdit {
639                         [MonoTODO]
640                         get {
641                                 return AllowEdit;
642                         }
643                 }
644
645                 bool IBindingList.AllowNew {
646                         [MonoTODO]
647                         get {
648                                 return AllowNew;
649                         }
650                 }
651
652                 bool IBindingList.AllowRemove {
653                         [MonoTODO]
654                         get {
655                                 return AllowDelete;
656                         }
657                 }
658
659                 bool IBindingList.IsSorted {
660                         [MonoTODO]
661                         get {
662                                 return isSorted;
663                         }
664                 }
665
666                 ListSortDirection IBindingList.SortDirection {
667                         [MonoTODO]
668                         get {
669                                 // FIXME: 
670                                 return ListSortDirection.Ascending;
671                         }
672                 }
673
674                 PropertyDescriptor IBindingList.SortProperty {
675                         [MonoTODO]
676                         get {
677                                 // FIXME:
678                                 return null;
679                         }
680                 }
681
682                 bool IBindingList.SupportsChangeNotification {
683                         [MonoTODO]
684                         get {
685                                 return false;
686                         }
687                 }
688
689                 bool IBindingList.SupportsSearching {
690                         [MonoTODO]
691                         get {
692                                 return false;
693                         }
694                 }
695
696                 bool IBindingList.SupportsSorting {
697                         [MonoTODO]
698                         get {
699                                 return false;
700                         }
701                 }
702
703                 #endregion // IBindingList implementation
704
705                 private class DataViewEnumerator : IEnumerator 
706                 {
707                         private DataRowView[] rows;
708                         int on = -1;
709
710                         internal DataViewEnumerator (DataRowView[] dataRowViews) 
711                         {
712                                 rows = dataRowViews;
713                         }
714
715                         public object Current {
716                                 get {
717                                         if (on == -1 || on >= rows.Length)
718                                                 throw new InvalidOperationException ();
719                                         return rows[on];
720                                 }
721                         }
722
723                         public bool MoveNext () 
724                         {
725                                 // TODO: how do you determine
726                                 // if a collection has been
727                                 // changed?
728                                 if (on < rows.Length - 1) {
729                                         on++;
730                                         return true;
731                                 }
732
733                                 return false; // EOF
734                         }
735
736                         public void Reset () {
737                                 on = -1;
738                         }
739                 }
740         }
741 }
742