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