2003-11-25 Tim Coleman <tim@timcoleman.com>
[mono.git] / mcs / class / System.Data / System.Data / DataTableCollection.cs
1 //
2 // System.Data.DataTableCollection.cs
3 //
4 // Authors:
5 //   Christopher Podurgiel (cpodurgiel@msn.com)
6 //   Tim Coleman <tim@timcoleman.com>
7 //
8 // (C) Chris Podurgiel
9 // (C) Copyright 2002 Tim Coleman
10 //
11
12 using System;
13 using System.Collections;
14 using System.ComponentModel;
15 using System.Globalization;
16
17 namespace System.Data {
18         /// <summary>
19         /// Represents the collection of tables for the DataSet.
20         /// </summary>
21         [Editor]
22         [DefaultEvent ("CollectionChanged")]
23         [ListBindable (false)]
24         [Serializable]
25         public class DataTableCollection : InternalDataCollectionBase
26         {
27                 DataSet dataSet;
28                 
29                 #region Constructors 
30
31                 internal DataTableCollection (DataSet dataSet)
32                         : base ()
33                 {
34                         this.dataSet = dataSet;
35                 }
36                 
37                 #endregion
38                 
39                 #region Properties
40
41                 public DataTable this[int index] {
42                         get { return (DataTable)(list[index]); }
43                 }
44
45                 public DataTable this[string name] {
46                         get { 
47                                 int index = IndexOf (name, true);
48                                 return index < 0 ? null : (DataTable) list[index];
49                         }
50                 }
51
52                 protected override ArrayList List {
53                         get { return list; }
54                 }
55
56                 #endregion
57         
58                 #region Methods 
59
60                 public virtual DataTable Add () 
61                 {
62                         DataTable Table = new DataTable ();
63                         Add (Table);
64                         return Table;
65                 }
66
67                 public virtual void Add (DataTable table) 
68                 {
69                         
70                         // check if the reference is a null reference
71                         if(table == null)
72                                 throw new ArgumentNullException("table");
73             
74                         // check if the list already contains this tabe.
75                         if(list.Contains(table))
76                                 throw new ArgumentException("DataTable already belongs to this DataSet.");
77             
78                         // if the table name is null or empty string.
79                         // give her a name. 
80                         if (table.TableName == null || table.TableName == string.Empty)
81                                 NameTable (table);
82                     
83                         // check if the collection has a table with the same name.
84                         if(Contains(table.TableName))
85                                 throw new DuplicateNameException("A DataTable named '" + table.TableName + "' already belongs to this DataSet.");
86                                 
87                         list.Add (table);
88                         table.dataSet = dataSet;
89                         OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, table));
90                 }
91
92                 public virtual DataTable Add (string name) 
93                 {
94                         DataTable table = new DataTable (name);
95                         this.Add (table);
96                         return table;
97                 }
98
99                 public void AddRange (DataTable[] tables) 
100                 {
101                         foreach (DataTable table in tables)
102                                 this.Add (table);
103                 }
104
105                 [MonoTODO]
106                 public bool CanRemove (DataTable table) 
107                 {
108                         return CanRemove(table, false);
109                 }
110
111                 public void Clear () 
112                 {
113                         list.Clear ();
114                 }
115
116                 public bool Contains (string name) 
117                 {
118                         return (-1 != IndexOf (name, false));
119                 }
120
121                 public virtual int IndexOf (DataTable table) 
122                 {
123                         return list.IndexOf (table);
124                 }
125
126                 public virtual int IndexOf (string name) 
127                 {
128                         return IndexOf (name, false);
129                 }
130
131                 public void Remove (DataTable table) 
132                 {
133                         CanRemove(table, true);
134                         list.Remove(table);
135                         OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, table));
136                 }
137
138                 public void Remove (string name) 
139                 {
140                         Remove (this [name]);
141                 }
142
143                 public void RemoveAt (int index) 
144                 {
145                         DataTable t = this[index];
146                         CanRemove(t, true);
147                         list.RemoveAt (index);
148                         OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, t));
149                 }
150
151                 #endregion
152
153                 #region Protected methods
154
155                 protected internal virtual void OnCollectionChanging (CollectionChangeEventArgs Args)
156                 {
157                         if (CollectionChanging != null)
158                                 CollectionChanging (this, Args);
159                 }
160
161                 protected virtual void OnCollectionChanged (CollectionChangeEventArgs Args)
162                 {
163                         if (CollectionChanged != null)
164                                 CollectionChanged (this, Args);
165                 }
166
167                 #endregion
168
169                 #region Private methods
170
171                 private int IndexOf (string name, bool error)
172                 {
173                         int count = 0, match = -1;
174                         for (int i = 0; i < list.Count; i++)
175                         {
176                                 String name2 = ((DataTable) list[i]).TableName;
177                                 if (String.Compare (name, name2, true) == 0)
178                                 {
179                                         if (String.Compare (name, name2, false) == 0)
180                                                 return i;
181                                         match = i;
182                                         count++;
183                                 }
184                         }
185                         if (count == 1)
186                                 return match;
187                         if (count > 1 && error)
188                                 throw new ArgumentException ("There is no match for the name in the same case and there are multiple matches in different case.");
189                         return -1;
190                 }
191
192                 /// <summary>
193                 /// gives name to Table (Table1, Table2, Table3,...)
194                 /// </summary>
195                 private void NameTable (DataTable Table)
196                 {
197                         string Name = "Table";
198                         int i = 1;
199                         while (Contains (Name + i))
200                                 i++;
201
202                         Table.TableName = Name + i;                            
203                 }
204                 
205                 // check if a table can be removed from this collectiuon.
206                 // if the table can not be remved act according to throwException parameter.
207                 // if it is true throws an Exception, else return false.
208                 private bool CanRemove(DataTable table, bool throwException)
209                 {
210                         // check if table is null reference
211                         if (table == null)
212                         {
213                                 if(throwException)
214                                         throw new ArgumentNullException("table");
215                                 return false;
216                         }
217                         
218                         // check if the table has the same DataSet as this collection.
219                         if(table.DataSet != this.dataSet)
220                         {
221                                 if(throwException)
222                                         throw new ArgumentException("Table " + table.TableName + " does not belong to this DataSet.");
223                                 return false;
224                         }
225                         
226                         // check the table has a relation attached to it.
227                         if (table.ParentRelations.Count > 0 || table.ChildRelations.Count > 0)
228                         {
229                                 if(throwException)
230                                         throw new ArgumentException("Cannot remove a table that has existing relations. Remove relations first.");
231                                 return false;
232                         }
233                         
234
235                         // now we check if any ForeignKeyConstraint is referncing 'table'.
236                         IEnumerator tableEnumerator = this.dataSet.Tables.GetEnumerator();
237                         
238                         // loop on all tables in dataset
239                         while (tableEnumerator.MoveNext())
240                         {
241                                 IEnumerator constraintEnumerator = ((DataTable) tableEnumerator.Current).Constraints.GetEnumerator();
242                                 // loop on all constrains in the current table
243                                 while (constraintEnumerator.MoveNext())
244                                 {
245                                         Object o = constraintEnumerator.Current;
246                                         // we only check ForeignKeyConstraint
247                                         if (o is ForeignKeyConstraint)
248                                         {
249                                                 ForeignKeyConstraint fc = (ForeignKeyConstraint) o;
250                                                 if(fc.Table == table || fc.RelatedTable == table)
251                                                 {
252                                                         if(throwException)
253                                                                 throw new ArgumentException("Cannot remove table " + table.TableName + ", because it referenced in ForeignKeyConstraint " + fc.ConstraintName + ". Remove the constraint first.");
254                                                         return false;
255                                                 }
256                                         }
257                                 }
258                         }
259
260                         return true;
261                 }
262
263                 #endregion // Private methods
264
265                 #region Events
266
267                 [ResDescriptionAttribute ("Occurs whenever this collection's membership changes.")]             
268                 public event CollectionChangeEventHandler CollectionChanged;
269
270                 public event CollectionChangeEventHandler CollectionChanging;
271
272                 #endregion
273         }
274 }