Wed Feb 24 15:47:16 CET 2010 Paolo Molaro <lupus@ximian.com>
[mono.git] / mcs / class / System.Web / System.Web.UI / StateManagedCollection.cs
1 //
2 // System.Web.UI.StateManagedCollection
3 //
4 // Authors:
5 //      Ben Maurer (bmaurer@users.sourceforge.net)
6 //      Sebastien Pouliot  <sebastien@ximian.com>
7 //      Marek Habersack (mhabersack@novell.com)
8 //
9 // (C) 2003 Ben Maurer
10 // Copyright (C) 2005-2008 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.Collections;
33 using System.Collections.Generic;
34
35 namespace System.Web.UI {
36
37         public abstract class StateManagedCollection : IList, IStateManager
38         {               
39                 ArrayList items = new ArrayList ();
40                 bool saveEverything = false;
41
42                 protected virtual object CreateKnownType (int index)
43                 {
44                         return null;
45                 }
46
47                 public void SetDirty ()
48                 {
49                         saveEverything = true;
50                         for (int i = 0; i < items.Count; i++)
51                                 SetDirtyObject (items[i]);
52                 }
53
54                 protected abstract void SetDirtyObject (object o);
55
56                 protected virtual Type [] GetKnownTypes ()
57                 {
58                         return null;
59                 }
60                 
61                 #region OnXXX
62                 protected virtual void OnClear ()
63                 {
64                 }
65                 
66                 protected virtual void OnClearComplete ()
67                 {
68                 }
69                 
70                 protected virtual void OnInsert (int index, object value)
71                 {
72                 }
73                 
74                 protected virtual void OnInsertComplete (int index, object value)
75                 {
76                 }
77                 
78                 protected virtual void OnRemove (int index, object value)
79                 {
80                 }
81                 
82                 protected virtual void OnRemoveComplete (int index, object value)
83                 {
84                 }
85                 
86                 protected virtual void OnValidate (object value)
87                 {
88                         if (value == null)
89                                 throw new ArgumentNullException ("value");
90                 }
91                 #endregion
92                 
93                 #region IStateManager
94                 void IStateManager.LoadViewState (object savedState)
95                 {
96                         if (savedState == null) {
97                                 foreach (IStateManager i in items)
98                                         i.LoadViewState (null);
99                                 return;
100                         }
101
102                         Triplet state = savedState as Triplet;
103                         if (state == null)
104                                 throw new InvalidOperationException ("Internal error.");
105
106                         List <int> indices = state.First as List <int>;
107                         List <object> states = state.Second as List <object>;
108                         List <object> types = state.Third as List <object>;
109                         IList list = this as IList;
110                         IStateManager item;
111                         object t;
112                         
113                         saveEverything = indices == null;
114                         if (saveEverything) {
115                                 items.Clear ();
116
117                                 for (int i = 0; i < states.Count; i++) {
118                                         t = types [i];
119                                         if (t is Type)
120                                                 item = (IStateManager) Activator.CreateInstance ((Type) t);
121                                         else if (t is int)
122                                                 item = (IStateManager) CreateKnownType ((int) t);
123                                         else
124                                                 continue;
125
126                                         item.TrackViewState ();
127                                         item.LoadViewState (states [i]);
128                                         list.Add (item);
129                                 }
130                                 return;
131                         }
132
133                         int idx;
134                         for (int i = 0; i < indices.Count; i++) {
135                                 idx = indices [i];
136
137                                 if (idx < Count) {
138                                         item = list [idx] as IStateManager;
139                                         item.TrackViewState ();
140                                         item.LoadViewState (states [i]);
141                                         continue;
142                                 }
143
144                                 t = types [i];
145
146                                 if (t is Type)
147                                         item = (IStateManager) Activator.CreateInstance ((Type) t);
148                                 else if (t is int)
149                                         item = (IStateManager) CreateKnownType ((int) t);
150                                 else
151                                         continue;
152
153                                 item.TrackViewState ();
154                                 item.LoadViewState (states [i]);
155                                 list.Add (item);
156                         }
157                 }
158                 
159                 void AddListItem <T> (ref List <T> list, T item)
160                 {
161                         if (list == null)
162                                 list = new List <T> ();
163
164                         list.Add (item);
165                 }
166                         
167                 object IStateManager.SaveViewState ()
168                 {
169                         Type[] knownTypes = GetKnownTypes ();
170                         bool haveData = false, haveKnownTypes = knownTypes != null && knownTypes.Length > 0;
171                         int count = items.Count;
172                         IStateManager item;
173                         object itemState;
174                         Type type;
175                         int idx;
176                         List <int> indices = null;
177                         List <object> states = null;
178                         List <object> types = null;
179
180                         for (int i = 0; i < count; i++) {
181                                 item = items [i] as IStateManager;
182                                 if (item == null)
183                                         continue;
184                                 item.TrackViewState ();
185                                 itemState = item.SaveViewState ();
186                                 if (saveEverything || itemState != null) {
187                                         haveData = true;
188                                         type = item.GetType ();
189                                         idx = haveKnownTypes ? Array.IndexOf (knownTypes, type) : -1;
190
191                                         if (!saveEverything)
192                                                 AddListItem <int> (ref indices, i);
193                                         AddListItem <object> (ref states, itemState);
194                                         if (idx == -1)
195                                                 AddListItem <object> (ref types, type);
196                                         else
197                                                 AddListItem <object> (ref types, idx);
198                                 }
199                         }
200
201                         if (!haveData)
202                                 return null;
203
204                         return new Triplet (indices, states, types);
205                 }               
206                 
207                 void IStateManager.TrackViewState ()
208                 {
209                         isTrackingViewState = true;
210                         if (items != null && items.Count > 0) {
211                                 IStateManager item;
212                                 foreach (object o in items) {
213                                         item = o as IStateManager;
214                                         if (item == null)
215                                                 continue;
216                                         item.TrackViewState ();
217                                 }
218                         }
219                 }
220                 
221                 bool isTrackingViewState;
222                 bool IStateManager.IsTrackingViewState {
223                         get { return isTrackingViewState; }
224                 }
225                 #endregion
226                 
227                 #region ICollection, IList, IEnumerable
228                 
229                 public void Clear ()
230                 {
231                         this.OnClear ();
232                         items.Clear ();
233                         this.OnClearComplete ();
234                         
235                         if (isTrackingViewState)
236                                 SetDirty ();
237                 }
238                 
239                 public IEnumerator GetEnumerator ()
240                 {
241                         return items.GetEnumerator ();
242                 }
243                 
244                 public void CopyTo (Array array, int index)
245                 {
246                         items.CopyTo (array, index);
247                 }
248                 
249                 IEnumerator IEnumerable.GetEnumerator ()
250                 {
251                         return GetEnumerator ();
252                 }
253                 
254                 int IList.Add (object value)
255                 {
256                         OnValidate(value);
257                         if (isTrackingViewState) {
258                                 ((IStateManager) value).TrackViewState ();
259                                 SetDirtyObject (value);
260                         }
261                         
262                         OnInsert (-1, value);
263                         items.Add (value);
264                         OnInsertComplete (-1, value);
265                         
266                         return Count - 1;
267                 }
268                 
269                 void IList.Insert (int index, object value)
270                 {
271                         OnValidate(value);
272                         if (isTrackingViewState) {
273                                 ((IStateManager) value).TrackViewState ();
274                                 SetDirty ();
275                         }
276                         
277                         OnInsert (index, value);
278                         items.Insert (index, value);
279                         OnInsertComplete(index, value);
280                 }
281                 
282                 void IList.Remove (object value)
283                 {
284                         if (value == null)
285                                 return;
286                         OnValidate (value);
287                         IList list = (IList)this;
288                         int i = list.IndexOf (value);
289                         if (i >= 0)
290                                 list.RemoveAt (i);
291                 }
292
293                 void IList.RemoveAt (int index)
294                 {
295                         object o = items [index];
296                         
297                         OnRemove (index, o);
298                         items.RemoveAt (index);
299                         OnRemoveComplete(index, o);
300                         
301                         if (isTrackingViewState)
302                                 SetDirty ();
303                 }
304                         
305                 void IList.Clear ()
306                 {
307                         this.Clear ();
308                 }
309                 
310                 bool IList.Contains (object value)
311                 {
312                         if (value == null)
313                                 return false;
314                         
315                         OnValidate (value);
316                         return items.Contains (value);
317                 }
318                 
319                 int IList.IndexOf (object value)
320                 {
321                         if (value == null)
322                                 return -1;
323                         
324                         OnValidate (value);
325                         return items.IndexOf (value);
326                 }
327
328                 public int Count {
329                         get { return items.Count; }
330                 }
331                 
332                 int ICollection.Count {
333                         get { return items.Count; }
334                 }
335                 
336                 bool ICollection.IsSynchronized {
337                         get { return false; }
338                 }
339                 
340                 object ICollection.SyncRoot {
341                         get { return this; }
342                 }
343                 
344                 bool IList.IsFixedSize {
345                         get { return false; }
346                 }
347                 
348                 bool IList.IsReadOnly {
349                         get { return false; }
350                 }
351                 
352                 object IList.this [int index] {
353                         get { return items [index]; }
354                         set {
355                                 if (index < 0 || index >= Count)
356                                         throw new ArgumentOutOfRangeException ("index");
357                                 
358                                 OnValidate (value);
359                                 if (isTrackingViewState) {
360                                         ((IStateManager) value).TrackViewState ();
361                                         SetDirty ();
362                                 }
363                                 
364                                 items [index] = value;
365                         }
366                 }
367                 #endregion
368         }
369 }
370