* DataList.cs: Remove some debugging code that was starting to bug
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / DataList.cs
1 //
2 // System.Web.UI.WebControls.DataList.cs
3 //
4 // Author:
5 //      Sebastien Pouliot  <sebastien@ximian.com>
6 //
7 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System.Collections;
30 using System.ComponentModel;
31 using System.Globalization;
32 using System.Security.Permissions;
33 using System.Web.Util;
34
35 namespace System.Web.UI.WebControls {
36
37         // CAS
38         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
39         [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
40         // attributes
41         [Designer ("System.Web.UI.Design.WebControls.DataListDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
42 #if NET_2_0
43         [ControlValueProperty ("SelectedValue")]
44         [Editor ("System.Web.UI.Design.WebControls.DataListComponentEditor, " + Consts.AssemblySystem_Design, "System.ComponentModel.ComponentEditor, " + Consts.AssemblySystem)]
45 #else
46         [Editor ("System.Web.UI.Design.WebControls.DataListComponentEditor, " + Consts.AssemblySystem_Design, typeof (System.ComponentModel.ComponentEditor))]
47 #endif
48         public class DataList : BaseDataList, INamingContainer, IRepeatInfoUser {
49
50                 public const string CancelCommandName = "Cancel";
51                 public const string DeleteCommandName = "Delete";
52                 public const string EditCommandName = "Edit";
53                 public const string SelectCommandName = "Select";
54                 public const string UpdateCommandName = "Update";
55
56
57                 private static readonly object cancelCommandEvent = new object ();
58                 private static readonly object deleteCommandEvent = new object ();
59                 private static readonly object editCommandEvent = new object ();
60                 private static readonly object itemCommandEvent = new object ();
61                 private static readonly object itemCreatedEvent = new object ();
62                 private static readonly object itemDataBoundEvent = new object ();
63                 private static readonly object updateCommandEvent = new object ();
64
65                 private TableItemStyle alternatingItemStyle;
66                 private TableItemStyle editItemStyle;
67                 private TableItemStyle footerStyle;
68                 private TableItemStyle headerStyle;
69                 private TableItemStyle itemStyle;
70                 private TableItemStyle selectedItemStyle;
71                 private TableItemStyle separatorStyle;
72
73                 private ITemplate alternatingItemTemplate;
74                 private ITemplate editItemTemplate;
75                 private ITemplate footerTemplate;
76                 private ITemplate headerTemplate;
77                 private ITemplate itemTemplate;
78                 private ITemplate selectedItemTemplate;
79                 private ITemplate separatorTemplate;
80
81                 private DataListItemCollection items;
82                 private ArrayList list;
83                 private int idx;
84
85 #if NET_2_0
86                 private int editIndex;
87                 private int selectedIndex;
88
89                 public DataList ()
90                 {
91                         editIndex = -1;
92                         selectedIndex = -1;
93                         idx = -1;
94                 }
95 #else
96                 public DataList ()
97                 {
98                         idx = -1;
99                 }
100 #endif
101
102
103                 [DefaultValue (null)]
104                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
105                 [NotifyParentProperty (true)]
106                 [PersistenceMode (PersistenceMode.InnerProperty)]
107                 public virtual TableItemStyle AlternatingItemStyle {
108                         get {
109                                 if (alternatingItemStyle == null) {
110                                         alternatingItemStyle = new TableItemStyle ();
111                                         if (IsTrackingViewState) {
112                                                 alternatingItemStyle.TrackViewState ();
113                                         }
114                                 }
115                                 return alternatingItemStyle;
116                         }
117                 }
118
119                 [Browsable (false)]
120                 [DefaultValue (null)]
121                 [TemplateContainer (typeof (DataListItem))]
122                 [PersistenceMode (PersistenceMode.InnerProperty)]
123                 public virtual ITemplate AlternatingItemTemplate {
124                         get { return alternatingItemTemplate; }
125                         set { alternatingItemTemplate = value; }
126                 }
127
128                 [DefaultValue (-1)]
129                 public virtual int EditItemIndex {
130 #if NET_2_0
131                         get { return editIndex; }
132                         set {
133                                 if (value < -1)
134                                         throw new ArgumentOutOfRangeException ("EditItemIndex", "< -1");
135                                 editIndex = value;
136                         }
137 #else
138                         get {
139                                 object o = ViewState ["EditItemIndex"];
140                                 return (o == null) ? -1 : (int) o;
141                         }
142                         set {
143                                 if (value < -1)
144                                         throw new ArgumentOutOfRangeException ("EditItemIndex", "< -1");
145                                 ViewState ["EditItemIndex"] = value;
146                         }
147 #endif
148                 }
149
150                 [DefaultValue (null)]
151                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
152                 [NotifyParentProperty (true)]
153                 [PersistenceMode (PersistenceMode.InnerProperty)]
154                 public virtual TableItemStyle EditItemStyle {
155                         get {
156                                 if (editItemStyle == null) {
157                                         editItemStyle = new TableItemStyle ();
158                                         if (IsTrackingViewState) {
159                                                 editItemStyle.TrackViewState ();
160                                         }
161                                 }
162                                 return editItemStyle;
163                         }
164                 }
165
166                 [Browsable (false)]
167                 [DefaultValue (null)]
168                 [TemplateContainer (typeof (DataListItem))]
169                 [PersistenceMode (PersistenceMode.InnerProperty)]
170                 public virtual ITemplate EditItemTemplate {
171                         get { return editItemTemplate; }
172                         set { editItemTemplate = value; }
173                 }
174
175                 [DefaultValue (false)]
176                 public virtual bool ExtractTemplateRows {
177                         get {
178                                 object o = ViewState ["ExtractTemplateRows"];
179                                 return (o == null) ? false : (bool) o;
180                         }
181                         set { ViewState ["ExtractTemplateRows"] = value; }
182                 }
183
184                 [DefaultValue (null)]
185                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
186                 [NotifyParentProperty (true)]
187                 [PersistenceMode (PersistenceMode.InnerProperty)]
188                 public virtual TableItemStyle FooterStyle {
189                         get {
190                                 if (footerStyle == null) {
191                                         footerStyle = new TableItemStyle ();
192                                         if (IsTrackingViewState) {
193                                                 footerStyle.TrackViewState ();
194                                         }
195                                 }
196                                 return footerStyle;
197                         }
198                 }
199
200                 [Browsable (false)]
201                 [DefaultValue (null)]
202                 [TemplateContainer (typeof (DataListItem))]
203                 [PersistenceMode (PersistenceMode.InnerProperty)]
204                 public virtual ITemplate FooterTemplate {
205                         get { return footerTemplate; }
206                         set { footerTemplate = value; }
207                 }
208
209                 // yes! they do NOT match in fx1.1
210                 [DefaultValue (GridLines.None)]
211                 public override GridLines GridLines {
212                         get {
213                                 if (!ControlStyleCreated) {
214 #if NET_2_0
215                                         return GridLines.None;
216 #else
217                                         return GridLines.Both;
218 #endif
219                                 }
220                                 return TableStyle.GridLines;
221                         }
222                         set { TableStyle.GridLines = value; }
223                 }
224
225                 [DefaultValue (null)]
226                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
227                 [NotifyParentProperty (true)]
228                 [PersistenceMode (PersistenceMode.InnerProperty)]
229                 public virtual TableItemStyle HeaderStyle {
230                         get {
231                                 if (headerStyle == null) {
232                                         headerStyle = new TableItemStyle ();
233                                         if (IsTrackingViewState) {
234                                                 headerStyle.TrackViewState ();
235                                         }
236                                 }
237                                 return headerStyle;
238                         }
239                 }
240
241                 [Browsable (false)]
242                 [DefaultValue (null)]
243                 [TemplateContainer (typeof (DataListItem))]
244                 [PersistenceMode (PersistenceMode.InnerProperty)]
245                 public virtual ITemplate HeaderTemplate {
246                         get { return headerTemplate; }
247                         set { headerTemplate = value; }
248                 }
249
250                 [Browsable (false)]
251                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
252                 public virtual DataListItemCollection Items {
253                         get {
254                                 if (items == null)
255                                         items = new DataListItemCollection (ItemList);
256                                 return items;
257                         }
258                 }
259
260                 [DefaultValue (null)]
261                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
262                 [NotifyParentProperty (true)]
263                 [PersistenceMode (PersistenceMode.InnerProperty)]
264                 public virtual TableItemStyle ItemStyle {
265                         get {
266                                 if (itemStyle == null) {
267                                         itemStyle = new TableItemStyle ();
268                                         if (IsTrackingViewState) {
269                                                 itemStyle.TrackViewState ();
270                                         }
271                                 }
272                                 return itemStyle;
273                         }
274                 }
275
276                 [Browsable (false)]
277                 [DefaultValue (null)]
278                 [TemplateContainer (typeof (DataListItem))]
279                 [PersistenceMode (PersistenceMode.InnerProperty)]
280                 public virtual ITemplate ItemTemplate {
281                         get { return itemTemplate; }
282                         set { itemTemplate = value; }
283                 }
284
285 #if ONLY_1_1
286                 [Bindable (true)]
287 #endif
288                 [DefaultValue (0)]
289                 public virtual int RepeatColumns {
290                         get {
291                                 object o = ViewState ["RepeatColumns"];
292                                 return (o == null) ? 0 : (int) o;
293                         }
294                         set { ViewState ["RepeatColumns"] = value; }
295                 }
296
297 #if ONLY_1_1
298                 [Bindable (true)]
299 #endif
300                 [DefaultValue (RepeatDirection.Vertical)]
301                 public virtual RepeatDirection RepeatDirection {
302                         get {
303                                 object o = ViewState ["RepeatDirection"];
304                                 return (o == null) ? RepeatDirection.Vertical : (RepeatDirection) o;
305                         }
306                         set { ViewState ["RepeatDirection"] = value; }
307                 }
308
309 #if ONLY_1_1
310                 [Bindable (true)]
311 #endif
312                 [DefaultValue (RepeatLayout.Table)]
313                 public virtual RepeatLayout RepeatLayout {
314                         get {
315                                 object o = ViewState ["RepeatLayout"];
316                                 return (o == null) ? RepeatLayout.Table : (RepeatLayout) o;
317                         }
318                         set { ViewState ["RepeatLayout"] = value; }
319                 }
320
321                 [Bindable (true)]
322                 [DefaultValue (-1)]
323                 public virtual int SelectedIndex {
324 #if NET_2_0
325                         get { return selectedIndex; }
326                         set {
327                                 if (value < -1)
328                                         throw new ArgumentOutOfRangeException ("SelectedIndex", "< -1");
329                                 selectedIndex = value;
330                         }
331 #else
332                         get {
333                                 object o = ViewState ["SelectedIndex"];
334                                 return (o == null) ? -1 : (int) o;
335                         }
336                         set {
337                                 if (value < -1)
338                                         throw new ArgumentOutOfRangeException ("SelectedIndex", "< -1");
339                                 ViewState ["SelectedIndex"] = value;
340                         }
341 #endif
342                 }
343
344                 [Browsable (false)]
345                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
346                 public virtual DataListItem SelectedItem {
347                         get {
348                                 if (SelectedIndex < 0)
349                                         return null;
350                                 if (SelectedIndex >= Items.Count)
351                                         throw new ArgumentOutOfRangeException ("SelectedItem", ">= Items.Count");
352                                 return items [SelectedIndex];
353                         }
354                 }
355
356                 [DefaultValue (null)]
357                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
358                 [NotifyParentProperty (true)]
359                 [PersistenceMode (PersistenceMode.InnerProperty)]
360                 public virtual TableItemStyle SelectedItemStyle {
361                         get {
362                                 if (selectedItemStyle == null) {
363                                         selectedItemStyle = new TableItemStyle ();
364                                         if (IsTrackingViewState) {
365                                                 selectedItemStyle.TrackViewState ();
366                                         }
367                                 }
368                                 return selectedItemStyle;
369                         }
370                 }
371
372                 [Browsable (false)]
373                 [DefaultValue (null)]
374                 [TemplateContainer (typeof (DataListItem))]
375                 [PersistenceMode (PersistenceMode.InnerProperty)]
376                 public virtual ITemplate SelectedItemTemplate {
377                         get { return selectedItemTemplate; }
378                         set { selectedItemTemplate = value; }
379                 }
380
381                 [DefaultValue (null)]
382                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
383                 [NotifyParentProperty (true)]
384                 [PersistenceMode (PersistenceMode.InnerProperty)]
385                 public virtual TableItemStyle SeparatorStyle {
386                         get {
387                                 if (separatorStyle == null) {
388                                         separatorStyle = new TableItemStyle ();
389                                         if (IsTrackingViewState) {
390                                                 separatorStyle.TrackViewState ();
391                                         }
392                                 }
393                                 return separatorStyle;
394                         }
395                 }
396
397                 [Browsable (false)]
398                 [DefaultValue (null)]
399                 [TemplateContainer (typeof (DataListItem))]
400                 [PersistenceMode (PersistenceMode.InnerProperty)]
401                 public virtual ITemplate SeparatorTemplate {
402                         get { return separatorTemplate; }
403                         set { separatorTemplate = value; }
404                 }
405
406 #if ONLY_1_1
407                 [Bindable (true)]
408 #endif
409                 [DefaultValue (true)]
410                 public virtual bool ShowFooter {
411                         get {
412                                 object o = ViewState ["ShowFooter"];
413                                 return (o == null) ? true : (bool) o;
414                         }
415                         set { ViewState ["ShowFooter"] = value; }
416                 }
417
418 #if ONLY_1_1
419                 [Bindable (true)]
420 #endif
421                 [DefaultValue (true)]
422                 public virtual bool ShowHeader {
423                         get {
424                                 object o = ViewState ["ShowHeader"];
425                                 return (o == null) ? true : (bool) o;
426                         }
427                         set { ViewState ["ShowHeader"] = value; }
428                 }
429
430 #if NET_2_0
431                 [MonoTODO ("incomplete")]
432                 [Browsable (false)]
433                 public object SelectedValue {
434                         get {
435                                 if (DataKeyField.Length == 0)
436                                         throw new InvalidOperationException (Locale.GetText ("No DataKeyField present."));
437
438                                 if ((SelectedIndex >= 0) && (selectedIndex < DataKeys.Count)) {
439                                         return DataKeys [selectedIndex];
440                                 }
441
442                                 return null;
443                         }
444                 }
445
446                 protected override HtmlTextWriterTag TagKey {
447                         get { return HtmlTextWriterTag.Table; }
448                 }
449 #endif
450
451                 private TableStyle TableStyle {
452                         // this will throw an InvalidCasException just like we need
453                         get { return (TableStyle) ControlStyle; }
454                 }
455                 
456                 private ArrayList ItemList {
457                         get {
458                                 if (list == null)
459                                         list = new ArrayList ();
460                                 return list;
461                         }
462                 }
463
464                 void DoItem (int i, ListItemType t, object d, bool databind)
465                 {
466                         DataListItem itm = CreateItem (i, t);
467                         itm.DataItem = d;
468                         DataListItemEventArgs e = new DataListItemEventArgs (itm);
469                         InitializeItem (itm);
470                         
471                         //
472                         // It is very important that this be called *before* data
473                         // binding. Otherwise, we won't save our state in the viewstate.
474                         //
475                         Controls.Add (itm);
476                         if (i != -1)
477                                 ItemList.Add (itm);
478                         OnItemCreated (e);
479
480                         if (databind) {
481                                 itm.DataBind ();
482                                 OnItemDataBound (e);
483                         }
484                 }
485
486                 private void DoItemInLoop (int i, object d, bool databind)
487                 {
488                         if (i > 0 && SeparatorTemplate != null)
489                                 DoItem (i - 1, ListItemType.Separator, null, databind);
490
491                         DoItem (i, i % 2 == 0 ? ListItemType.Item : ListItemType.AlternatingItem, d, databind);
492                 }
493
494                 protected override void CreateControlHierarchy (bool useDataSource)
495                 {
496                         Controls.Clear();
497
498                         IEnumerable ds = null;
499
500                         if (useDataSource) {
501                                 idx = 0;
502                                 ds = DataSourceResolver.ResolveDataSource (DataSource, DataMember);
503                         } else {
504                                 idx = (int) ViewState ["Items"];
505                         }
506
507                         if ((ds == null) && (idx == 0))
508                                 return;
509
510                         if (headerTemplate != null)
511                                 DoItem (-1, ListItemType.Header, null, useDataSource);
512
513                         // items
514                         if (ds != null) {
515                                 foreach (object o in ds) {
516                                         DoItemInLoop (idx, o, useDataSource);
517                                         idx++;
518                                 }
519                         } else {
520                                 for (int i = 0; i < idx; i++) {
521                                         DoItemInLoop (i, null, useDataSource);
522                                 }
523                         }
524
525                         if (footerTemplate != null)
526                                 DoItem (-1, ListItemType.Footer, null, useDataSource);
527
528                         ViewState ["Items"] = idx;
529                 }
530
531                 protected override Style CreateControlStyle ()
532                 {
533 #if NET_2_0
534                         // not kept (directly) in the DataList ViewState
535                         return new TableStyle ();
536 #else
537                         return new TableStyle (ViewState);
538 #endif
539                 }
540
541                 protected virtual DataListItem CreateItem (int itemIndex, ListItemType itemType)
542                 {
543                         return new DataListItem (itemIndex, itemType);
544                 }
545
546                 protected virtual void InitializeItem (DataListItem item)
547                 {
548                         ITemplate t = null;
549                         
550                         switch (item.ItemType) {
551                         case ListItemType.Header:
552                                 t = HeaderTemplate;
553                                 break;
554                         case ListItemType.Footer:
555                                 t = FooterTemplate;
556                                 break;  
557                         case ListItemType.Separator:
558                                 t = SeparatorTemplate;
559                                 break;
560                         case ListItemType.Item:
561                         case ListItemType.AlternatingItem:
562                         case ListItemType.SelectedItem:
563                         case ListItemType.EditItem:
564                                 int index = item.ItemIndex;
565                                 if (SelectedIndex == index)
566                                         t = SelectedItemTemplate;
567                                 else if (EditItemIndex == index)
568                                         t = EditItemTemplate;
569                                 else if (((index & 1) == 0) || (alternatingItemTemplate == null))
570                                         t = ItemTemplate;
571                                 else
572                                         t = alternatingItemTemplate;
573                                 break;
574                         }
575
576                         if (t != null)
577                                 t.InstantiateIn (item);
578                 }
579
580                 protected override void LoadViewState (object savedState)
581                 {
582                         object[] state = (object[]) savedState;
583                         base.LoadViewState (state [0]);
584                         if (state [1] != null)
585                                 ItemStyle.LoadViewState (state [1]);
586                         if (state [2] != null)
587                                 SelectedItemStyle.LoadViewState (state [2]);
588                         if (state [3] != null)
589                                 AlternatingItemStyle.LoadViewState (state [3]);
590                         if (state [4] != null)
591                                 EditItemStyle.LoadViewState (state [4]);
592                         if (state [5] != null)
593                                 SeparatorStyle.LoadViewState (state [5]);
594                         if (state [6] != null)
595                                 HeaderStyle.LoadViewState (state [6]);
596                         if (state [7] != null)
597                                 FooterStyle.LoadViewState (state [7]);
598                 }
599 #if NET_2_0
600                 protected internal override void LoadControlState (object savedState)
601                 {
602                         // FIXME: what's in Triplet.First ?
603                         // ??? maybe a some space for base.LoadControlState ???
604                         if (savedState == null) {
605                                 // reset to default values
606                                 editIndex = -1;
607                                 selectedIndex = -1;
608                         } else {
609                                 Triplet t = (Triplet) savedState;
610                                 if (t.Second == null) {
611                                         editIndex = -1;
612                                 } else {
613                                         editIndex = (int) t.Second;
614                                 }
615                                 if (t.Third == null) {
616                                         selectedIndex = -1;
617                                 } else {
618                                         selectedIndex = (int) t.Third;
619                                 }
620                         }
621                 }
622
623                 protected internal override object SaveControlState ()
624                 {
625                         bool e = (editIndex == -1);
626                         bool s = (selectedIndex == -1);
627                         if (e && s)
628                                 return null;
629
630                         Triplet t = new Triplet ();
631                         if (!e)
632                                 t.Second = editIndex;
633                         if (!s)
634                                 t.Third = selectedIndex;
635                         
636                         return (object) t;
637                 }
638 #endif
639                 protected override bool OnBubbleEvent (object source, EventArgs e)
640                 {
641                         DataListCommandEventArgs dlca = (e as DataListCommandEventArgs);
642                         if (dlca == null)
643                                 return false;
644
645                         string cn = dlca.CommandName;
646                         CultureInfo inv = CultureInfo.InvariantCulture;
647
648                         if (String.Compare (cn, CancelCommandName, true, inv) == 0) {
649                                 OnCancelCommand (dlca);
650                                 return true;
651                         } else if (String.Compare (cn, DeleteCommandName, true, inv) == 0) {
652                                 OnDeleteCommand (dlca);
653                                 return true;
654                         } else if (String.Compare (cn, EditCommandName, true, inv) == 0) {
655                                 OnEditCommand (dlca);
656                                 return true;
657                         } else if (String.Compare (cn, SelectCommandName, true, inv) == 0) {
658                                 OnSelectedIndexChanged (dlca);
659                                 return true;
660                         } else if (String.Compare (cn, UpdateCommandName, true, inv) == 0) {
661                                 OnUpdateCommand (dlca);
662                                 return true;
663                         } else if (String.Compare (cn, "ITEM", true, inv) == 0) {
664                                 OnItemCommand (dlca);
665                                 return true;
666                         }
667                                                 
668                         return false;
669                 }
670
671                 protected virtual void OnCancelCommand (DataListCommandEventArgs e)
672                 {
673                         DataListCommandEventHandler cancelCommand = (DataListCommandEventHandler) Events [cancelCommandEvent];
674                         if (cancelCommand != null)
675                                 cancelCommand (this, e);
676                 }
677
678                 protected virtual void OnDeleteCommand (DataListCommandEventArgs e)
679                 {
680                         DataListCommandEventHandler deleteCommand = (DataListCommandEventHandler) Events [deleteCommandEvent];
681                         if (deleteCommand != null)
682                                 deleteCommand (this, e);
683                 }
684
685                 protected virtual void OnEditCommand (DataListCommandEventArgs e)
686                 {
687                         DataListCommandEventHandler editCommand = (DataListCommandEventHandler) Events [editCommandEvent];
688                         if (editCommand != null)
689                                 editCommand (this, e);
690                 }
691 #if NET_2_0
692                 protected internal override void OnInit (EventArgs e)
693                 {
694                         // EditItemIndex and SelectedIndex now use the Control State (i.e not the View State)
695                         Page.RegisterRequiresControlState (this);
696                         base.OnInit (e);
697                 }
698 #endif
699                 protected virtual void OnItemCommand (DataListCommandEventArgs e)
700                 {
701                         DataListCommandEventHandler itemCommand = (DataListCommandEventHandler) Events [itemCommandEvent];
702                         if (itemCommand != null)
703                                 itemCommand (this, e);
704                 }
705
706                 protected virtual void OnItemCreated (DataListItemEventArgs e)
707                 {
708                         DataListItemEventHandler itemCreated = (DataListItemEventHandler) Events [itemCreatedEvent];
709                         if (itemCreated != null)
710                                 itemCreated (this, e);
711                 }
712
713                 protected virtual void OnItemDataBound (DataListItemEventArgs e)
714                 {
715                         DataListItemEventHandler itemDataBound = (DataListItemEventHandler) Events [itemDataBoundEvent];
716                         if (itemDataBound != null)
717                                 itemDataBound (this, e);
718                 }
719
720                 protected virtual void OnUpdateCommand (DataListCommandEventArgs e)
721                 {
722                         DataListCommandEventHandler updateCommand = (DataListCommandEventHandler) Events [updateCommandEvent];
723                         if (updateCommand != null)
724                                 updateCommand (this, e);
725                 }
726
727                 protected override void PrepareControlHierarchy ()
728                 {
729                 }
730
731 #if NET_2_0
732                 protected internal
733 #else           
734                 protected
735 #endif          
736                 override void RenderContents (HtmlTextWriter writer)
737                 {
738                         RepeatInfo ri = new RepeatInfo ();
739                         ri.RepeatColumns = RepeatColumns;
740                         ri.RepeatDirection = RepeatDirection;
741                         ri.RepeatLayout = RepeatLayout;
742 /*
743 // debugging stuff that I prefer to keep for a while
744 Console.WriteLine ("RepeatColumns {0}", ri.RepeatColumns);
745 Console.WriteLine ("RepeatDirection {0}", ri.RepeatDirection);
746 Console.WriteLine ("RepeatLayout {0}", ri.RepeatLayout);
747 Console.WriteLine ("OuterTableImplied {0}", ExtractTemplateRows);
748 Console.WriteLine ("IRepeatInfoUser.HasFooter {0}", (ShowFooter && (footerTemplate != null)));
749 Console.WriteLine ("IRepeatInfoUser.HasHeader {0}", (ShowHeader && (headerTemplate != null)));
750 Console.WriteLine ("IRepeatInfoUser.HasSeparators {0}", (separatorTemplate != null));
751 Console.WriteLine ("IRepeatInfoUser.RepeatedItemCount {0}", Items.Count);
752 for (int i=0; i < Items.Count; i++) {
753         DataListItem dli = Items [i];
754         Console.WriteLine ("{0}: Index {1}, Type {2}", i, dli.ItemIndex, dli.ItemType);
755 }
756 */
757                         bool extract = ExtractTemplateRows;
758                         if (extract) {
759                                 ri.OuterTableImplied = true;
760                                 writer.AddAttribute (HtmlTextWriterAttribute.Id, ID);
761                                 if (ControlStyleCreated) {
762                                         ControlStyle.AddAttributesToRender (writer);
763                                 }
764                                 writer.RenderBeginTag (HtmlTextWriterTag.Table);
765                                 ri.RenderRepeater (writer, this, TableStyle, this);
766                                 writer.RenderEndTag ();
767                         } else {
768                                 ri.RenderRepeater (writer, this, TableStyle, this);
769                         }
770                 }
771
772                 protected override object SaveViewState ()
773                 {
774 #if NET_2_0
775                         object[] state = new object [9];
776                         // FIXME: what's new in slot #0 ?
777                         state[8] = base.SaveViewState ();
778 #else
779                         object[] state = new object [8];
780                         state[0] = base.SaveViewState ();
781 #endif
782                         if (itemStyle != null)
783                                 state [1] = itemStyle.SaveViewState ();
784                         if (selectedItemStyle != null)
785                                 state [2] = selectedItemStyle.SaveViewState ();
786                         if (alternatingItemStyle != null)
787                                 state [3] = alternatingItemStyle.SaveViewState ();
788                         if (editItemStyle != null)
789                                 state [4] = editItemStyle.SaveViewState ();
790                         if (separatorStyle != null)
791                                 state [5] = separatorStyle.SaveViewState ();
792                         if (headerStyle != null)
793                                 state [6] = headerStyle.SaveViewState ();
794                         if (footerStyle != null)
795                                 state [7] = footerStyle.SaveViewState ();
796                         return state;
797                 }
798
799                 protected override void TrackViewState ()
800                 {
801                         base.TrackViewState ();
802                         if (alternatingItemStyle != null)
803                                 alternatingItemStyle.TrackViewState ();
804                         if (editItemStyle != null)
805                                 editItemStyle.TrackViewState ();
806                         if (footerStyle != null)
807                                 footerStyle.TrackViewState ();
808                         if (headerStyle != null)
809                                 headerStyle.TrackViewState ();
810                         if (itemStyle != null)
811                                 itemStyle.TrackViewState ();
812                         if (selectedItemStyle != null)
813                                 selectedItemStyle.TrackViewState ();
814                         if (separatorStyle != null)
815                                 separatorStyle.TrackViewState ();
816                 }
817
818
819                 public event DataListCommandEventHandler CancelCommand {
820                         add { Events.AddHandler (cancelCommandEvent, value); }
821                         remove { Events.RemoveHandler (cancelCommandEvent, value); }
822                 }
823
824                 public event DataListCommandEventHandler DeleteCommand {
825                         add { Events.AddHandler (deleteCommandEvent, value); }
826                         remove { Events.RemoveHandler (deleteCommandEvent, value); }
827                 }
828
829                 public event DataListCommandEventHandler EditCommand {
830                         add { Events.AddHandler (editCommandEvent, value); }
831                         remove { Events.RemoveHandler (editCommandEvent, value); }
832                 }
833
834                 public event DataListCommandEventHandler ItemCommand {
835                         add { Events.AddHandler (itemCommandEvent, value); }
836                         remove { Events.RemoveHandler (itemCommandEvent, value); }
837                 }
838
839                 public event DataListItemEventHandler ItemCreated {
840                         add { Events.AddHandler (itemCreatedEvent, value); }
841                         remove { Events.RemoveHandler (itemCreatedEvent, value); }
842                 }
843
844                 public event DataListItemEventHandler ItemDataBound {
845                         add { Events.AddHandler (itemDataBoundEvent, value); }
846                         remove { Events.RemoveHandler (itemDataBoundEvent, value); }
847                 }
848
849                 public event DataListCommandEventHandler UpdateCommand {
850                         add { Events.AddHandler (updateCommandEvent, value); }
851                         remove { Events.RemoveHandler (updateCommandEvent, value); }
852                 }
853
854
855                 // IRepeatInfoUser support
856
857                 bool IRepeatInfoUser.HasFooter {
858                         get { return (ShowFooter && (footerTemplate != null)); }
859                 }
860
861                 bool IRepeatInfoUser.HasHeader {
862                         get { return (ShowHeader && (headerTemplate != null)); }
863                 }
864                 
865                 bool IRepeatInfoUser.HasSeparators {
866                         get { return (separatorTemplate != null); }
867                 }
868
869                 // don't include header, footer and separators in the count
870                 int IRepeatInfoUser.RepeatedItemCount {
871                         get {
872                                 if (idx == -1) {
873                                         object o = ViewState ["Items"];
874                                         idx = (o == null) ? 0 : (int) o;
875                                 }
876                                 return idx;
877                         }
878                 }
879
880                 Style IRepeatInfoUser.GetItemStyle (ListItemType itemType, int repeatIndex)
881                 {
882                         switch (itemType) {
883                         case ListItemType.Header:
884                                 if (repeatIndex >= Items.Count)
885                                         throw new ArgumentOutOfRangeException ("repeatIndex");
886                                 return headerStyle;
887                         case ListItemType.Footer:
888                                 if (repeatIndex >= Items.Count)
889                                         throw new ArgumentOutOfRangeException ("repeatIndex");
890                                 return footerStyle;
891                         case ListItemType.Item:
892                         case ListItemType.AlternatingItem:
893                         case ListItemType.SelectedItem:
894                         case ListItemType.EditItem:
895                                 if (repeatIndex >= Items.Count)
896                                         throw new ArgumentOutOfRangeException ("repeatIndex");
897
898                                 if (SelectedIndex == repeatIndex)
899                                         return selectedItemStyle;
900
901                                 if (EditItemIndex == repeatIndex)
902                                         return editItemStyle;
903
904                                 if (((repeatIndex & 1) == 0) || (alternatingItemStyle == null))
905                                         return itemStyle;
906
907                                 // alternate style
908                                 TableItemStyle alt = new TableItemStyle ();
909                                 alt.CopyFrom (itemStyle);
910                                 alt.CopyFrom (alternatingItemStyle);
911                                 return alt;
912                         case ListItemType.Separator:
913                                 if (repeatIndex >= Items.Count)
914                                         throw new ArgumentOutOfRangeException ("repeatIndex");
915                                 return separatorStyle;
916                         default:
917                                 return null;
918                         }
919                 }
920
921                 // Header and Footer don't have a "real" index (-1)
922                 private DataListItem FindFirstItem (ListItemType itemType)
923                 {
924                         for (int i = 0; i < Controls.Count; i++) {
925                                 DataListItem item = (Controls [i] as DataListItem);
926                                 if ((item != null) && (item.ItemType == itemType))
927                                         return item;
928                         }
929                         return null;
930                 }
931
932                 // Both Type and Index must match (e.g. Separator)
933                 private DataListItem FindSpecificItem (ListItemType itemType, int repeatIndex)
934                 {
935                         for (int i = 0; i < Controls.Count; i++) {
936                                 DataListItem item = (Controls [i] as DataListItem);
937                                 if ((item != null) && (item.ItemType == itemType) && (item.ItemIndex == repeatIndex))
938                                         return item;
939                         }
940                         return null;
941                 }
942
943                 // we get call for Item even for AlternatingItem :(
944                 private DataListItem FindBestItem (int repeatIndex)
945                 {
946                         for (int i = 0; i < Controls.Count; i++) {
947                                 DataListItem item = (Controls [i] as DataListItem);
948                                 if ((item != null) && (item.ItemIndex == repeatIndex)) {
949                                         switch (item.ItemType) {
950                                         case ListItemType.Item:
951                                         case ListItemType.AlternatingItem:
952                                         case ListItemType.SelectedItem:
953                                         case ListItemType.EditItem:
954                                                 return item;
955                                         default:
956                                                 return null;
957                                         }
958                                 }
959                         }
960                         return null;
961                 }
962
963                 void IRepeatInfoUser.RenderItem (ListItemType itemType, int repeatIndex, RepeatInfo repeatInfo, HtmlTextWriter writer)
964                 {
965                         // if possible take the easy way out...
966                         if (!HasControls ())
967                                 return;
968
969                         DataListItem item = null;
970                         switch (itemType) {
971                         case ListItemType.Header:
972                         case ListItemType.Footer:
973                                 item = FindFirstItem (itemType);
974                                 break;
975                         case ListItemType.Item:
976                         case ListItemType.AlternatingItem:
977                         case ListItemType.SelectedItem:
978                         case ListItemType.EditItem:
979                                 item = FindBestItem (repeatIndex);
980                                 break;
981                         case ListItemType.Separator:
982                                 item = FindSpecificItem (itemType, repeatIndex);
983                                 break;
984                         }
985
986                         if (item != null) {
987                                 bool extract = ExtractTemplateRows;
988                                 bool table = (RepeatLayout == RepeatLayout.Table);
989                                 if (!table || extract) {
990                                         // sadly RepeatInfo doesn't support Style for RepeatLayout.Flow
991                                         Style s = (this as IRepeatInfoUser).GetItemStyle (itemType, repeatIndex);
992                                         if (s != null)
993                                                 item.ControlStyle.CopyFrom (s);
994                                 }
995 //Console.WriteLine ("RenderItem #{0} type {1}", repeatIndex, itemType);
996                                 item.RenderItem (writer, extract, table);
997                         } else {
998 //Console.WriteLine ("Couldn't find #{0} type {1} out of {2} items / {3} controls", repeatIndex, itemType, Items.Count, Controls.Count);
999                         }
1000                 }
1001         }
1002 }