* DataList.cs: fixed RepeatColumns property, added value validation
[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 { 
314                                 if (value < 0)
315                                         throw new ArgumentOutOfRangeException ("value", "RepeatColumns value has to be 0 for 'not set' or > 0.");
316                                 
317                                 ViewState ["RepeatColumns"] = value; 
318                         }
319                 }
320
321 #if ONLY_1_1
322                 [Bindable (true)]
323 #endif
324                 [DefaultValue (RepeatDirection.Vertical)]
325                 [WebSysDescription ("")]
326                 [WebCategory ("Layout")]
327                 public virtual RepeatDirection RepeatDirection {
328                         get {
329                                 object o = ViewState ["RepeatDirection"];
330                                 return (o == null) ? RepeatDirection.Vertical : (RepeatDirection) o;
331                         }
332                         set { ViewState ["RepeatDirection"] = value; }
333                 }
334
335 #if ONLY_1_1
336                 [Bindable (true)]
337 #endif
338                 [DefaultValue (RepeatLayout.Table)]
339                 [WebSysDescription ("")]
340                 [WebCategory ("Layout")]
341                 public virtual RepeatLayout RepeatLayout {
342                         get {
343                                 object o = ViewState ["RepeatLayout"];
344                                 return (o == null) ? RepeatLayout.Table : (RepeatLayout) o;
345                         }
346                         set { ViewState ["RepeatLayout"] = value; }
347                 }
348
349                 [Bindable (true)]
350                 [DefaultValue (-1)]
351                 [WebSysDescription ("")]
352                 [WebCategory ("Layout")]
353                 public virtual int SelectedIndex {
354                         get {
355                                 object o = ViewState ["SelectedIndex"];
356                                 return (o == null) ? -1 : (int) o;
357                         }
358                         set {
359                                 if (value < -1)
360                                         throw new ArgumentOutOfRangeException ("SelectedIndex", "< -1");
361                                 ViewState ["SelectedIndex"] = value;
362                         }
363                 }
364
365                 [Browsable (false)]
366                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
367                 [WebSysDescription ("")]
368                 [WebCategory ("Layout")]
369                 public virtual DataListItem SelectedItem {
370                         get {
371                                 if (SelectedIndex < 0)
372                                         return null;
373                                 if (SelectedIndex >= Items.Count)
374                                         throw new ArgumentOutOfRangeException ("SelectedItem", ">= Items.Count");
375                                 return items [SelectedIndex];
376                         }
377                 }
378
379                 [DefaultValue (null)]
380                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
381                 [NotifyParentProperty (true)]
382                 [PersistenceMode (PersistenceMode.InnerProperty)]
383                 [WebSysDescription ("")]
384                 [WebCategory ("Style")]
385                 public virtual TableItemStyle SelectedItemStyle {
386                         get {
387                                 if (selectedItemStyle == null) {
388                                         selectedItemStyle = new TableItemStyle ();
389                                         if (IsTrackingViewState) {
390                                                 selectedItemStyle.TrackViewState ();
391                                         }
392                                 }
393                                 return selectedItemStyle;
394                         }
395                 }
396
397                 [Browsable (false)]
398                 [DefaultValue (null)]
399                 [TemplateContainer (typeof (DataListItem))]
400                 [PersistenceMode (PersistenceMode.InnerProperty)]
401                 [WebSysDescription ("")]
402                 [WebCategory ("Style")]
403                 public virtual ITemplate SelectedItemTemplate {
404                         get { return selectedItemTemplate; }
405                         set { selectedItemTemplate = value; }
406                 }
407
408                 [DefaultValue (null)]
409                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
410                 [NotifyParentProperty (true)]
411                 [PersistenceMode (PersistenceMode.InnerProperty)]
412                 [WebSysDescription ("")]
413                 [WebCategory ("Style")]
414                 public virtual TableItemStyle SeparatorStyle {
415                         get {
416                                 if (separatorStyle == null) {
417                                         separatorStyle = new TableItemStyle ();
418                                         if (IsTrackingViewState) {
419                                                 separatorStyle.TrackViewState ();
420                                         }
421                                 }
422                                 return separatorStyle;
423                         }
424                 }
425
426                 [Browsable (false)]
427                 [DefaultValue (null)]
428                 [TemplateContainer (typeof (DataListItem))]
429                 [PersistenceMode (PersistenceMode.InnerProperty)]
430                 [WebSysDescription ("")]
431                 [WebCategory ("Style")]
432                 public virtual ITemplate SeparatorTemplate {
433                         get { return separatorTemplate; }
434                         set { separatorTemplate = value; }
435                 }
436
437 #if ONLY_1_1
438                 [Bindable (true)]
439 #endif
440                 [DefaultValue (true)]
441                 [WebSysDescription ("")]
442                 [WebCategory ("Appearance")]
443                 public virtual bool ShowFooter {
444                         get {
445                                 object o = ViewState ["ShowFooter"];
446                                 return (o == null) ? true : (bool) o;
447                         }
448                         set { ViewState ["ShowFooter"] = value; }
449                 }
450
451 #if ONLY_1_1
452                 [Bindable (true)]
453 #endif
454                 [DefaultValue (true)]
455                 [WebSysDescription ("")]
456                 [WebCategory ("Appearance")]
457                 public virtual bool ShowHeader {
458                         get {
459                                 object o = ViewState ["ShowHeader"];
460                                 return (o == null) ? true : (bool) o;
461                         }
462                         set { ViewState ["ShowHeader"] = value; }
463                 }
464
465 #if NET_2_0
466                 [MonoTODO ("incomplete")]
467                 [Browsable (false)]
468                 public object SelectedValue {
469                         get {
470                                 if (DataKeyField.Length == 0)
471                                         throw new InvalidOperationException (Locale.GetText ("No DataKeyField present."));
472
473                                 if ((SelectedIndex >= 0) && (selectedIndex < DataKeys.Count)) {
474                                         return DataKeys [selectedIndex];
475                                 }
476
477                                 return null;
478                         }
479                 }
480
481                 protected override HtmlTextWriterTag TagKey {
482                         get { return HtmlTextWriterTag.Table; }
483                 }
484 #endif
485
486                 private TableStyle TableStyle {
487                         // this will throw an InvalidCasException just like we need
488                         get { return (TableStyle) ControlStyle; }
489                 }
490                 
491                 private ArrayList ItemList {
492                         get {
493                                 if (list == null)
494                                         list = new ArrayList ();
495                                 return list;
496                         }
497                 }
498
499                 void DoItem (int i, ListItemType t, object d, bool databind)
500                 {
501                         DataListItem itm = CreateItem (i, t);
502                         if (databind)
503                                 itm.DataItem = d;
504                         DataListItemEventArgs e = new DataListItemEventArgs (itm);
505                         InitializeItem (itm);
506                         
507                         //
508                         // It is very important that this be called *before* data
509                         // binding. Otherwise, we won't save our state in the viewstate.
510                         //
511                         Controls.Add (itm);
512                         if (i != -1)
513                                 ItemList.Add (itm);
514
515                         OnItemCreated (e);
516
517                         if (databind) {
518                                 itm.DataBind ();
519                                 OnItemDataBound (e);
520                                 itm.DataItem = null;
521                         }
522                 }
523
524                 private void DoItemInLoop (int i, object d, bool databind, ListItemType type)
525                 {
526                         DoItem (i, type, d, databind);
527                         if (SeparatorTemplate != null)
528                                 DoItem (i, ListItemType.Separator, null, databind);
529
530                 }
531
532                 protected override void CreateControlHierarchy (bool useDataSource)
533                 {
534                         Controls.Clear();
535
536                         IEnumerable ds = null;
537                         ArrayList keys = null;
538
539                         if (useDataSource) {
540                                 idx = 0;
541                                 ds = DataSourceResolver.ResolveDataSource (DataSource, DataMember);
542                                 keys = DataKeysArray;
543                                 keys.Clear ();
544                         } else {
545                                 idx = (int) ViewState ["Items"];
546                         }
547
548                         if ((ds == null) && (idx == 0))
549                                 return;
550
551                         if (headerTemplate != null)
552                                 DoItem (-1, ListItemType.Header, null, useDataSource);
553
554                         // items
555                         int selected_index = SelectedIndex;
556                         int edit_item_index = EditItemIndex;
557                         ListItemType type;
558                         if (ds != null) {
559                                 string key = DataKeyField;
560                                 foreach (object o in ds) {
561                                         if (useDataSource && key != "")
562                                                 keys.Add (DataBinder.GetPropertyValue (o, key));
563                                         type = ListItemType.Item;
564                                         if (idx == edit_item_index) 
565                                                 type = ListItemType.EditItem;
566                                         else if (idx == selected_index) 
567                                                 type = ListItemType.SelectedItem;
568                                         else if (idx % 2 != 0) 
569                                                 type = ListItemType.AlternatingItem;
570
571                                         DoItemInLoop (idx, o, useDataSource, type);
572                                         idx++;
573                                 }
574                         } else {
575                                 for (int i = 0; i < idx; i++) {
576                                         type = ListItemType.Item;
577                                         if (idx == edit_item_index) 
578                                                 type = ListItemType.EditItem;
579                                         else if (idx == selected_index) 
580                                                 type = ListItemType.SelectedItem;
581                                         else if (idx % 2 != 0) 
582                                                 type = ListItemType.AlternatingItem;
583
584                                         DoItemInLoop (i, null, useDataSource, type);
585                                 }
586                         }
587
588                         if (footerTemplate != null)
589                                 DoItem (-1, ListItemType.Footer, null, useDataSource);
590
591                         ViewState ["Items"] = idx;
592                 }
593
594                 protected override Style CreateControlStyle ()
595                 {
596 #if NET_2_0
597                         // not kept (directly) in the DataList ViewState
598                         return new TableStyle ();
599 #else
600                         TableStyle tableStyle = new TableStyle (ViewState);
601                         tableStyle.CellSpacing = 0;
602                         return tableStyle;
603 #endif
604                 }
605
606                 protected virtual DataListItem CreateItem (int itemIndex, ListItemType itemType)
607                 {
608                         return new DataListItem (itemIndex, itemType);
609                 }
610
611                 protected virtual void InitializeItem (DataListItem item)
612                 {
613                         ITemplate t = null;
614                         
615                         switch (item.ItemType) {
616                         case ListItemType.Header:
617                                 t = HeaderTemplate;
618                                 break;
619                         case ListItemType.Footer:
620                                 t = FooterTemplate;
621                                 break;  
622                         case ListItemType.Separator:
623                                 t = SeparatorTemplate;
624                                 break;
625                         case ListItemType.Item:
626                         case ListItemType.AlternatingItem:
627                         case ListItemType.SelectedItem:
628                         case ListItemType.EditItem:
629                                 int index = item.ItemIndex;
630                                 if ((SelectedIndex == index) && (SelectedItemTemplate != null))
631                                         t = SelectedItemTemplate;
632                                 else if ((EditItemIndex == index) && (EditItemTemplate != null))
633                                         t = EditItemTemplate;
634                                 else if (((index & 1) == 0) || (alternatingItemTemplate == null))
635                                         t = ItemTemplate;
636                                 else
637                                         t = alternatingItemTemplate;
638                                 break;
639                         }
640
641                         if (t != null)
642                                 t.InstantiateIn (item);
643                 }
644
645                 protected override void LoadViewState (object savedState)
646                 {
647                         object[] state = (object[]) savedState;
648                         base.LoadViewState (state [0]);
649                         if (state [1] != null)
650                                 ItemStyle.LoadViewState (state [1]);
651                         if (state [2] != null)
652                                 SelectedItemStyle.LoadViewState (state [2]);
653                         if (state [3] != null)
654                                 AlternatingItemStyle.LoadViewState (state [3]);
655                         if (state [4] != null)
656                                 EditItemStyle.LoadViewState (state [4]);
657                         if (state [5] != null)
658                                 SeparatorStyle.LoadViewState (state [5]);
659                         if (state [6] != null)
660                                 HeaderStyle.LoadViewState (state [6]);
661                         if (state [7] != null)
662                                 FooterStyle.LoadViewState (state [7]);
663                 }
664
665                 protected override bool OnBubbleEvent (object source, EventArgs e)
666                 {
667                         DataListCommandEventArgs dlca = (e as DataListCommandEventArgs);
668                         if (dlca == null)
669                                 return false;
670
671                         string cn = dlca.CommandName;
672                         CultureInfo inv = CultureInfo.InvariantCulture;
673
674                         OnItemCommand (dlca);
675                         if (String.Compare (cn, CancelCommandName, true, inv) == 0) {
676                                 OnCancelCommand (dlca);
677                                 return true;
678                         } else if (String.Compare (cn, DeleteCommandName, true, inv) == 0) {
679                                 OnDeleteCommand (dlca);
680                                 return true;
681                         } else if (String.Compare (cn, EditCommandName, true, inv) == 0) {
682                                 OnEditCommand (dlca);
683                                 return true;
684                         } else if (String.Compare (cn, SelectCommandName, true, inv) == 0) {
685                                 OnSelectedIndexChanged (dlca);
686                                 return true;
687                         } else if (String.Compare (cn, UpdateCommandName, true, inv) == 0) {
688                                 OnUpdateCommand (dlca);
689                                 return true;
690                         }
691                         return false;
692                 }
693
694                 protected virtual void OnCancelCommand (DataListCommandEventArgs e)
695                 {
696                         DataListCommandEventHandler cancelCommand = (DataListCommandEventHandler) Events [cancelCommandEvent];
697                         if (cancelCommand != null)
698                                 cancelCommand (this, e);
699                 }
700
701                 protected virtual void OnDeleteCommand (DataListCommandEventArgs e)
702                 {
703                         DataListCommandEventHandler deleteCommand = (DataListCommandEventHandler) Events [deleteCommandEvent];
704                         if (deleteCommand != null)
705                                 deleteCommand (this, e);
706                 }
707
708                 protected virtual void OnEditCommand (DataListCommandEventArgs e)
709                 {
710                         DataListCommandEventHandler editCommand = (DataListCommandEventHandler) Events [editCommandEvent];
711                         if (editCommand != null)
712                                 editCommand (this, e);
713                 }
714 #if NET_2_0
715                 protected internal override void OnInit (EventArgs e)
716                 {
717                         // EditItemIndex and SelectedIndex now use the Control State (i.e not the View State)
718                         Page.RegisterRequiresControlState (this);
719                         base.OnInit (e);
720                 }
721 #endif
722                 protected virtual void OnItemCommand (DataListCommandEventArgs e)
723                 {
724                         DataListCommandEventHandler itemCommand = (DataListCommandEventHandler) Events [itemCommandEvent];
725                         if (itemCommand != null)
726                                 itemCommand (this, e);
727                 }
728
729                 protected virtual void OnItemCreated (DataListItemEventArgs e)
730                 {
731                         DataListItemEventHandler itemCreated = (DataListItemEventHandler) Events [itemCreatedEvent];
732                         if (itemCreated != null)
733                                 itemCreated (this, e);
734                 }
735
736                 protected virtual void OnItemDataBound (DataListItemEventArgs e)
737                 {
738                         DataListItemEventHandler itemDataBound = (DataListItemEventHandler) Events [itemDataBoundEvent];
739                         if (itemDataBound != null)
740                                 itemDataBound (this, e);
741                 }
742
743                 protected virtual void OnUpdateCommand (DataListCommandEventArgs e)
744                 {
745                         DataListCommandEventHandler updateCommand = (DataListCommandEventHandler) Events [updateCommandEvent];
746                         if (updateCommand != null)
747                                 updateCommand (this, e);
748                 }
749
750                 void ApplyControlStyle (Control ctrl, Style style)
751                 {
752                         if (style == null || false == ctrl.HasControls ())
753                                 return;
754
755                         foreach (Control c in ctrl.Controls) {
756                                 if (c is Table) {
757                                         Table tbl = (Table) c;
758                                         foreach (TableRow row in tbl.Rows)
759                                                 row.MergeStyle (style);
760                                 }
761                         }
762                 }
763
764                 protected override void PrepareControlHierarchy ()
765                 {
766                         if (!HasControls () || Controls.Count == 0)
767                                 return; // No one called CreateControlHierarchy() with DataSource != null
768
769                         Style alt = null;
770                         foreach (DataListItem item in Controls) {
771                                 switch (item.ItemType) {
772                                 case ListItemType.Item:
773                                         item.MergeStyle (itemStyle);
774                                         ApplyControlStyle (item, itemStyle);
775                                         break;
776                                 case ListItemType.AlternatingItem:
777                                         if (alt == null) {
778                                                 if (alternatingItemStyle != null) {
779                                                         alt = new TableItemStyle ();
780                                                         alt.CopyFrom (itemStyle);
781                                                         alt.CopyFrom (alternatingItemStyle);
782                                                 } else {
783                                                         alt = itemStyle;
784                                                 }
785                                         }
786
787                                         item.MergeStyle (alt);
788                                         ApplyControlStyle (item, alt);
789                                         break;
790                                 case ListItemType.EditItem:
791                                         if (editItemStyle != null) {
792                                                 item.MergeStyle (editItemStyle);
793                                                 ApplyControlStyle (item, editItemStyle);
794                                         } else {
795                                                 item.MergeStyle (itemStyle);
796                                                 ApplyControlStyle (item, itemStyle);
797                                         }
798                                         break;
799                                 case ListItemType.Footer:
800                                         if (!ShowFooter) {
801                                                 item.Visible = false;
802                                                 break;
803                                         }
804                                         if (footerStyle != null) {
805                                                 item.MergeStyle (footerStyle);
806                                                 ApplyControlStyle (item, footerStyle);
807                                         }
808                                         break;
809                                 case ListItemType.Header:
810                                         if (!ShowHeader) {
811                                                 item.Visible = false;
812                                                 break;
813                                         }
814                                         if (headerStyle != null) {
815                                                 item.MergeStyle (headerStyle);
816                                                 ApplyControlStyle (item, headerStyle);
817                                         }
818                                         break;
819                                 case ListItemType.SelectedItem:
820                                         if (selectedItemStyle != null) {
821                                                 item.MergeStyle (selectedItemStyle);
822                                                 ApplyControlStyle (item, selectedItemStyle);
823                                         } else {
824                                                 item.MergeStyle (itemStyle);
825                                                 ApplyControlStyle (item, itemStyle);
826                                         }
827                                         break;
828                                 case ListItemType.Separator:
829                                         if (separatorStyle != null) {
830                                                 item.MergeStyle(separatorStyle);
831                                                 ApplyControlStyle (item, separatorStyle);
832                                         }
833                                         else {
834                                                 item.MergeStyle (itemStyle);
835                                                 ApplyControlStyle (item, itemStyle);
836                                         }
837                                         break;
838                                 }
839                         }
840                 }
841
842 #if NET_2_0
843                 protected internal
844 #else           
845                 protected
846 #endif          
847                 override void RenderContents (HtmlTextWriter writer)
848                 {
849                         if (Items.Count == 0)
850                                 return;                 
851
852                         RepeatInfo ri = new RepeatInfo ();
853                         ri.RepeatColumns = RepeatColumns;
854                         ri.RepeatDirection = RepeatDirection;
855                         ri.RepeatLayout = RepeatLayout;
856 /*
857 // debugging stuff that I prefer to keep for a while
858 Console.WriteLine ("RepeatColumns {0}", ri.RepeatColumns);
859 Console.WriteLine ("RepeatDirection {0}", ri.RepeatDirection);
860 Console.WriteLine ("RepeatLayout {0}", ri.RepeatLayout);
861 Console.WriteLine ("OuterTableImplied {0}", ExtractTemplateRows);
862 Console.WriteLine ("IRepeatInfoUser.HasFooter {0}", (ShowFooter && (footerTemplate != null)));
863 Console.WriteLine ("IRepeatInfoUser.HasHeader {0}", (ShowHeader && (headerTemplate != null)));
864 Console.WriteLine ("IRepeatInfoUser.HasSeparators {0}", (separatorTemplate != null));
865 Console.WriteLine ("IRepeatInfoUser.RepeatedItemCount {0}", Items.Count);
866 for (int i=0; i < Items.Count; i++) {
867         DataListItem dli = Items [i];
868         Console.WriteLine ("{0}: Index {1}, Type {2}", i, dli.ItemIndex, dli.ItemType);
869 }
870 */
871                         bool extract = ExtractTemplateRows;
872                         if (extract) {
873                                 ri.OuterTableImplied = true;
874                                 writer.AddAttribute (HtmlTextWriterAttribute.Id, ClientID);
875                                 if (ControlStyleCreated) {
876                                         ControlStyle.AddAttributesToRender (writer);
877                                 }
878                                 writer.RenderBeginTag (HtmlTextWriterTag.Table);
879                                 ri.RenderRepeater (writer, this, ControlStyle, this);
880                                 writer.RenderEndTag ();
881                         } else {
882                                 ri.RenderRepeater (writer, this, ControlStyle, this);
883                         }
884                 }
885
886                 protected override object SaveViewState ()
887                 {
888 #if NET_2_0
889                         object[] state = new object [9];
890                         // FIXME: what's new in slot #0 ?
891                         state[8] = base.SaveViewState ();
892 #else
893                         object[] state = new object [8];
894                         state[0] = base.SaveViewState ();
895 #endif
896                         if (itemStyle != null)
897                                 state [1] = itemStyle.SaveViewState ();
898                         if (selectedItemStyle != null)
899                                 state [2] = selectedItemStyle.SaveViewState ();
900                         if (alternatingItemStyle != null)
901                                 state [3] = alternatingItemStyle.SaveViewState ();
902                         if (editItemStyle != null)
903                                 state [4] = editItemStyle.SaveViewState ();
904                         if (separatorStyle != null)
905                                 state [5] = separatorStyle.SaveViewState ();
906                         if (headerStyle != null)
907                                 state [6] = headerStyle.SaveViewState ();
908                         if (footerStyle != null)
909                                 state [7] = footerStyle.SaveViewState ();
910                         return state;
911                 }
912
913                 protected override void TrackViewState ()
914                 {
915                         base.TrackViewState ();
916                         if (alternatingItemStyle != null)
917                                 alternatingItemStyle.TrackViewState ();
918                         if (editItemStyle != null)
919                                 editItemStyle.TrackViewState ();
920                         if (footerStyle != null)
921                                 footerStyle.TrackViewState ();
922                         if (headerStyle != null)
923                                 headerStyle.TrackViewState ();
924                         if (itemStyle != null)
925                                 itemStyle.TrackViewState ();
926                         if (selectedItemStyle != null)
927                                 selectedItemStyle.TrackViewState ();
928                         if (separatorStyle != null)
929                                 separatorStyle.TrackViewState ();
930                 }
931
932
933                 [WebSysDescription ("")]
934                 [WebCategory ("Action")]
935                 public event DataListCommandEventHandler CancelCommand {
936                         add { Events.AddHandler (cancelCommandEvent, value); }
937                         remove { Events.RemoveHandler (cancelCommandEvent, value); }
938                 }
939
940                 [WebSysDescription ("")]
941                 [WebCategory ("Action")]
942                 public event DataListCommandEventHandler DeleteCommand {
943                         add { Events.AddHandler (deleteCommandEvent, value); }
944                         remove { Events.RemoveHandler (deleteCommandEvent, value); }
945                 }
946
947                 [WebSysDescription ("")]
948                 [WebCategory ("Action")]
949                 public event DataListCommandEventHandler EditCommand {
950                         add { Events.AddHandler (editCommandEvent, value); }
951                         remove { Events.RemoveHandler (editCommandEvent, value); }
952                 }
953
954                 [WebSysDescription ("")]
955                 [WebCategory ("Action")]
956                 public event DataListCommandEventHandler ItemCommand {
957                         add { Events.AddHandler (itemCommandEvent, value); }
958                         remove { Events.RemoveHandler (itemCommandEvent, value); }
959                 }
960
961                 [WebSysDescription ("")]
962                 [WebCategory ("Action")]
963                 public event DataListItemEventHandler ItemCreated {
964                         add { Events.AddHandler (itemCreatedEvent, value); }
965                         remove { Events.RemoveHandler (itemCreatedEvent, value); }
966                 }
967
968                 [WebSysDescription ("")]
969                 [WebCategory ("Action")]
970                 public event DataListItemEventHandler ItemDataBound {
971                         add { Events.AddHandler (itemDataBoundEvent, value); }
972                         remove { Events.RemoveHandler (itemDataBoundEvent, value); }
973                 }
974
975                 [WebSysDescription ("")]
976                 [WebCategory ("Action")]
977                 public event DataListCommandEventHandler UpdateCommand {
978                         add { Events.AddHandler (updateCommandEvent, value); }
979                         remove { Events.RemoveHandler (updateCommandEvent, value); }
980                 }
981
982
983                 // IRepeatInfoUser support
984
985                 bool IRepeatInfoUser.HasFooter {
986                         get { return (ShowFooter && (footerTemplate != null)); }
987                 }
988
989                 bool IRepeatInfoUser.HasHeader {
990                         get { return (ShowHeader && (headerTemplate != null)); }
991                 }
992                 
993                 bool IRepeatInfoUser.HasSeparators {
994                         get { return (separatorTemplate != null); }
995                 }
996
997                 // don't include header, footer and separators in the count
998                 int IRepeatInfoUser.RepeatedItemCount {
999                         get {
1000                                 if (idx == -1) {
1001                                         object o = ViewState ["Items"];
1002                                         idx = (o == null) ? 0 : (int) o;
1003                                 }
1004                                 return idx;
1005                         }
1006                 }
1007
1008                 Style IRepeatInfoUser.GetItemStyle (ListItemType itemType, int repeatIndex)
1009                 {
1010                         DataListItem item = null;
1011                         switch (itemType) {
1012                         case ListItemType.Header:
1013                         case ListItemType.Footer:
1014                                 if (repeatIndex >= 0 && (!HasControls () || repeatIndex >= Controls.Count))
1015                                         throw new ArgumentOutOfRangeException ();
1016
1017                                 item = FindFirstItem (itemType);
1018                                 break;
1019                         case ListItemType.Item:
1020                         case ListItemType.AlternatingItem:
1021                         case ListItemType.SelectedItem:
1022                         case ListItemType.EditItem:
1023                                 if (repeatIndex >= 0 && (!HasControls () || repeatIndex >= Controls.Count))
1024                                         throw new ArgumentOutOfRangeException ();
1025
1026                                 item = FindBestItem (repeatIndex);
1027                                 break;
1028                         case ListItemType.Separator:
1029                                 if (repeatIndex >= 0 && (!HasControls () || repeatIndex >= Controls.Count))
1030                                         throw new ArgumentOutOfRangeException ();
1031
1032                                 item = FindSpecificItem (itemType, repeatIndex);
1033                                 break;
1034                         default:
1035                                 item = null;
1036                                 break;
1037                         }
1038
1039                         if (item == null || item.ControlStyleCreated == false)
1040                                 return null;
1041
1042                         return item.ControlStyle;
1043                 }
1044
1045                 // Header and Footer don't have a "real" index (-1)
1046                 private DataListItem FindFirstItem (ListItemType itemType)
1047                 {
1048                         for (int i = 0; i < Controls.Count; i++) {
1049                                 DataListItem item = (Controls [i] as DataListItem);
1050                                 if ((item != null) && (item.ItemType == itemType))
1051                                         return item;
1052                         }
1053                         return null;
1054                 }
1055
1056                 // Both Type and Index must match (e.g. Separator)
1057                 private DataListItem FindSpecificItem (ListItemType itemType, int repeatIndex)
1058                 {
1059                         for (int i = 0; i < Controls.Count; i++) {
1060                                 DataListItem item = (Controls [i] as DataListItem);
1061                                 if ((item != null) && (item.ItemType == itemType) && (item.ItemIndex == repeatIndex))
1062                                         return item;
1063                         }
1064                         return null;
1065                 }
1066
1067                 // we get call for Item even for AlternatingItem :(
1068                 private DataListItem FindBestItem (int repeatIndex)
1069                 {
1070                         for (int i = 0; i < Controls.Count; i++) {
1071                                 DataListItem item = (Controls [i] as DataListItem);
1072                                 if ((item != null) && (item.ItemIndex == repeatIndex)) {
1073                                         switch (item.ItemType) {
1074                                         case ListItemType.Item:
1075                                         case ListItemType.AlternatingItem:
1076                                         case ListItemType.SelectedItem:
1077                                         case ListItemType.EditItem:
1078                                                 return item;
1079                                         default:
1080                                                 return null;
1081                                         }
1082                                 }
1083                         }
1084                         return null;
1085                 }
1086
1087                 void IRepeatInfoUser.RenderItem (ListItemType itemType, int repeatIndex, RepeatInfo repeatInfo, HtmlTextWriter writer)
1088                 {
1089                         // if possible take the easy way out...
1090                         if (!HasControls ())
1091                                 return;
1092
1093                         DataListItem item = null;
1094                         switch (itemType) {
1095                         case ListItemType.Header:
1096                         case ListItemType.Footer:
1097                                 item = FindFirstItem (itemType);
1098                                 break;
1099                         case ListItemType.Item:
1100                         case ListItemType.AlternatingItem:
1101                         case ListItemType.SelectedItem:
1102                         case ListItemType.EditItem:
1103                                 item = FindBestItem (repeatIndex);
1104                                 break;
1105                         case ListItemType.Separator:
1106                                 item = FindSpecificItem (itemType, repeatIndex);
1107                                 break;
1108                         }
1109
1110                         if (item != null) {
1111                                 bool extract = ExtractTemplateRows;
1112                                 bool table = (RepeatLayout == RepeatLayout.Table);
1113                                 if (!table || extract) {
1114                                         // sadly RepeatInfo doesn't support Style for RepeatLayout.Flow
1115                                         Style s = (this as IRepeatInfoUser).GetItemStyle (itemType, repeatIndex);
1116                                         if (s != null)
1117                                                 item.ControlStyle.CopyFrom (s);
1118                                 }
1119 //Console.WriteLine ("RenderItem #{0} type {1}", repeatIndex, itemType);
1120                                 item.RenderItem (writer, extract, table);
1121                         } else {
1122 //Console.WriteLine ("Couldn't find #{0} type {1} out of {2} items / {3} controls", repeatIndex, itemType, Items.Count, Controls.Count);
1123                         }
1124                 }
1125         }
1126 }