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