2006-08-03 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / PagedDataSource.cs
1 // System.Web.UI.WebControls.PagedDataSource.cs
2 //
3 // Author: Duncan Mak (duncan@novell.com)
4 //         Jackson Harper  (jackson@ximian.com) 
5 //
6 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining
9 // a copy of this software and associated documentation files (the
10 // "Software"), to deal in the Software without restriction, including
11 // without limitation the rights to use, copy, modify, merge, publish,
12 // distribute, sublicense, and/or sell copies of the Software, and to
13 // permit persons to whom the Software is furnished to do so, subject to
14 // the following conditions:
15 // 
16 // The above copyright notice and this permission notice shall be
17 // included in all copies or substantial portions of the Software.
18 // 
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 //
27
28 using System.Collections;
29 using System.ComponentModel;
30 using System.Security.Permissions;
31
32 namespace System.Web.UI.WebControls {
33
34         // CAS - no inheritance demand required because the class is sealed
35         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
36         public sealed class PagedDataSource : ICollection, IEnumerable, ITypedList
37         {
38                 int page_size, current_page_index, virtual_count;
39                 bool allow_paging, allow_custom_paging, allow_server_paging;
40                 IEnumerable source;
41                 
42                 public PagedDataSource ()
43                 {
44                         page_size = 10;
45                 }
46
47                 public bool AllowCustomPaging {
48                         get { return allow_custom_paging; }
49                         set { 
50                                 allow_custom_paging = value; 
51 #if NET_2_0
52                                 // AllowCustomPaging and AllowServerPaging are mutually exclusive
53                                 if (allow_custom_paging)
54                                         allow_server_paging = false;
55 #endif
56                         }
57                 }
58
59                 public bool AllowPaging {
60                         get { return allow_paging; }
61                         set { allow_paging = value; }
62                 }
63
64                 public int Count {
65                         get {
66                                 if (source == null)
67                                         return 0;
68                                 
69                                 if (IsPagingEnabled) {
70                                         if (IsCustomPagingEnabled || !IsLastPage)
71                                                 return page_size;
72                                         return DataSourceCount - FirstIndexInPage;
73                                 }
74
75                                 return DataSourceCount;
76                         }
77                 }                                               
78
79                 public int CurrentPageIndex {
80                         get { return current_page_index; }
81                         set { current_page_index = value; }
82                 }
83
84                 public IEnumerable DataSource {
85                         get { return source; }
86                         set { source = value; }
87                 }
88
89                 public int DataSourceCount {
90                         get {
91                                 if (source == null)
92                                         return 0;
93                                 
94                                 if (IsCustomPagingEnabled 
95 #if NET_2_0
96                                     || IsServerPagingEnabled
97 #endif
98                                 )
99                                         return virtual_count;
100
101                                 if (source is ICollection)
102                                         return ((ICollection) source).Count;
103
104                                 throw new HttpException ("The data source must implement ICollection");
105                         }
106                 }
107
108                 public int FirstIndexInPage {
109                         get {
110                                 if (!IsPagingEnabled || IsCustomPagingEnabled || 
111 #if NET_2_0
112                                     IsServerPagingEnabled || 
113 #endif
114                                     source == null)
115                                         return 0;
116                                 
117                                 return current_page_index * page_size;
118                         }
119                 }
120
121                 public bool IsCustomPagingEnabled {
122                         get { return IsPagingEnabled && allow_custom_paging; }
123                 }
124
125 #if NET_2_0
126                 public bool IsServerPagingEnabled {
127                         get { return IsPagingEnabled && allow_server_paging; }
128                 }
129 #endif
130
131                 public bool IsFirstPage {
132                         get { 
133                                 if (!allow_paging)
134                                         return true;
135                                 
136                                 return current_page_index == 0; 
137                         }
138                 }
139
140                 public bool IsLastPage {
141                         get {
142                                 if (!allow_paging || page_size == 0)
143                                         return true;
144
145                                 return  (current_page_index == (PageCount - 1));
146                         }
147                 }
148
149                 public bool IsPagingEnabled {
150                         get { return (allow_paging && page_size != 0); }
151                 }
152
153                 public bool IsReadOnly {
154                         get { return false; } // as documented
155                 }
156
157                 public bool IsSynchronized {
158                         get { return false; } // as documented
159                 }
160
161                 public int PageCount {
162                         get {
163                                 if (source == null)
164                                         return 0;
165                                 
166                                 if (!IsPagingEnabled || DataSourceCount == 0 || page_size == 0)
167                                         return 1;
168                                 
169                                 return (DataSourceCount + page_size - 1) / page_size;
170                         }
171                 }
172                 
173                 public int PageSize {
174                         get { return page_size; }
175                         set { page_size = value; }
176                 }
177
178                 public object SyncRoot {
179                         get { return this; }
180                 }
181
182                 public int VirtualCount {
183                         get { return virtual_count; }
184                         set { virtual_count = value; }
185                 }
186 #if NET_2_0
187                 public bool AllowServerPaging {
188                         get {
189                                 return allow_server_paging;
190                         }
191                         set {
192                                 allow_server_paging = value;
193                                 // AllowCustomPaging and AllowServerPaging are mutually exclusive
194                                 if (allow_server_paging)
195                                         allow_custom_paging = false;
196                         }
197                 }
198 #endif
199
200                 public void CopyTo (Array array, int index)
201                 {
202                         foreach (object o in source)
203                                 array.SetValue (o, index++);
204                 }
205
206                 public IEnumerator GetEnumerator ()
207                 {
208                         // IList goes first, as it implements ICollection
209                         IList list = source as IList;
210                         int first = 0;
211                         int count;
212                         int limit;
213                         if (list != null) {
214                                 first = FirstIndexInPage;
215                                 count = ((ICollection) source).Count;
216                                 limit = ((first + page_size) > count) ? (count - first) : page_size;
217                                 return GetListEnum (list, first, first + limit);
218                         }
219
220                         ICollection col = source as ICollection;
221                         if (col != null) {
222                                 first = FirstIndexInPage;
223                                 count = col.Count;
224                                 limit = ((first + page_size) > count) ? (count - first) : page_size;
225                                 return GetEnumeratorEnum (col.GetEnumerator (), first, first + page_size);
226                         }
227
228                         return source.GetEnumerator ();
229                 }
230
231                 public PropertyDescriptorCollection GetItemProperties (PropertyDescriptor [] list_accessors)
232                 {
233                         ITypedList typed = source as ITypedList;
234                         if (typed == null)
235                                 return null;
236                         return typed.GetItemProperties (list_accessors);
237                 }
238
239                 public string GetListName (PropertyDescriptor [] list_accessors)
240                 {
241                         return String.Empty; // as documented
242                 }
243
244 #if TARGET_JVM
245                 internal class ListEnum : IEnumerator
246                 {
247                         int start;
248                         int end;
249                         int ind;
250                         IList list;
251
252                         internal ListEnum(IList list, int start, int end)
253                         {
254                                 this.list = list;
255                                 this.start = start;
256                                 this.end = end;
257                                 this.ind = start - 1;
258                         }
259
260                         public bool MoveNext()
261                         {
262                                 ind++;
263                                 return (ind < end);
264                         }
265
266                         public void Reset() { ind = start - 1; }
267                         public object Current { get { return list[ind]; }}
268                 }
269
270                 private IEnumerator GetListEnum (IList list, int start, int end)
271                 {
272                         if (!allow_paging)
273                                 end = list.Count;
274                         return new ListEnum(list, start, end);
275                 }
276
277                 internal class EnumeratorEnum : IEnumerator
278                 {
279                         int start;
280                         int end;
281                         int ind;
282                         IEnumerator en;
283                         PagedDataSource parent;
284
285                         internal EnumeratorEnum(PagedDataSource parent, IEnumerator en, int start, int end)
286                         {
287                                 this.parent = parent;
288                                 this.en = en;
289                                 this.start = start;
290                                 this.end = end;
291                                 this.ind = start - 1;
292                                 for (int i = 0; i < start; i++)
293                                         en.MoveNext ();
294                         }
295
296                         public bool MoveNext()
297                         {
298                                 ind++;
299                                 return (!parent.allow_paging || ind < end) && en.MoveNext ();
300                         }
301
302                         public void Reset()
303                         {
304                                 throw new NotSupportedException();
305                         }
306
307                         public object Current { get { return en.Current; }}
308                 }
309
310                 private IEnumerator GetEnumeratorEnum (IEnumerator e, int start, int end)
311                 {
312                         return new EnumeratorEnum(this, e, start, end);
313                 }
314 #else
315                 private IEnumerator GetListEnum (IList list, int start, int end)
316                 {
317                         if (!AllowPaging)
318                                 end = list.Count;
319                         else if (start >= list.Count)
320                                 yield break;
321                         
322                         for (int i = start; i < end; i++)
323                                 yield return list [i];
324                 }
325
326                 private IEnumerator GetEnumeratorEnum (IEnumerator e, int start, int end)
327                 {
328                         for (int i = 0; i < start; i++)
329                                 e.MoveNext ();
330                         for (int i = start; (!allow_paging || i < end) && e.MoveNext (); i++)
331                                 yield return e.Current;
332                 }
333 #endif
334         }
335 }
336