2005-10-10 Gonzalo Paniagua Javier <gonzalo@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                         if (databind)
498                                 itm.DataItem = d;
499                         DataListItemEventArgs e = new DataListItemEventArgs (itm);
500                         InitializeItem (itm);
501                         
502                         //
503                         // It is very important that this be called *before* data
504                         // binding. Otherwise, we won't save our state in the viewstate.
505                         //
506                         Controls.Add (itm);
507                         if (i != -1)
508                                 ItemList.Add (itm);
509
510                         OnItemCreated (e);
511
512                         if (databind) {
513                                 itm.DataBind ();
514                                 OnItemDataBound (e);
515                                 itm.DataItem = null;
516                         }
517                 }
518
519                 private void DoItemInLoop (int i, object d, bool databind, ListItemType type)
520                 {
521                         DoItem (i, type, d, databind);
522                         if (SeparatorTemplate != null)
523                                 DoItem (i - 1, ListItemType.Separator, null, databind);
524
525                 }
526
527                 protected override void CreateControlHierarchy (bool useDataSource)
528                 {
529                         Controls.Clear();
530
531                         IEnumerable ds = null;
532                         ArrayList keys = null;
533
534                         if (useDataSource) {
535                                 idx = 0;
536                                 ds = DataSourceResolver.ResolveDataSource (DataSource, DataMember);
537                                 keys = DataKeysArray;
538                                 keys.Clear ();
539                         } else {
540                                 idx = (int) ViewState ["Items"];
541                         }
542
543                         if ((ds == null) && (idx == 0))
544                                 return;
545
546                         if (headerTemplate != null)
547                                 DoItem (-1, ListItemType.Header, null, useDataSource);
548
549                         // items
550                         int selected_index = SelectedIndex;
551                         int edit_item_index = EditItemIndex;
552                         ListItemType type;
553                         if (ds != null) {
554                                 string key = DataKeyField;
555                                 foreach (object o in ds) {
556                                         if (useDataSource && key != "")
557                                                 keys.Add (DataBinder.GetPropertyValue (o, key));
558                                         type = ListItemType.Item;
559                                         if (idx == edit_item_index) 
560                                                 type = ListItemType.EditItem;
561                                         else if (idx == selected_index) 
562                                                 type = ListItemType.SelectedItem;
563                                         else if (idx % 2 != 0) 
564                                                 type = ListItemType.AlternatingItem;
565
566                                         DoItemInLoop (idx, o, useDataSource, type);
567                                         idx++;
568                                 }
569                         } else {
570                                 for (int i = 0; i < idx; i++) {
571                                         type = ListItemType.Item;
572                                         if (idx == edit_item_index) 
573                                                 type = ListItemType.EditItem;
574                                         else if (idx == selected_index) 
575                                                 type = ListItemType.SelectedItem;
576                                         else if (idx % 2 != 0) 
577                                                 type = ListItemType.AlternatingItem;
578
579                                         DoItemInLoop (i, null, useDataSource, type);
580                                 }
581                         }
582
583                         if (footerTemplate != null)
584                                 DoItem (-1, ListItemType.Footer, null, useDataSource);
585
586                         ViewState ["Items"] = idx;
587                 }
588
589                 protected override Style CreateControlStyle ()
590                 {
591 #if NET_2_0
592                         // not kept (directly) in the DataList ViewState
593                         return new TableStyle ();
594 #else
595                         return new TableStyle (ViewState);
596 #endif
597                 }
598
599                 protected virtual DataListItem CreateItem (int itemIndex, ListItemType itemType)
600                 {
601                         return new DataListItem (itemIndex, itemType);
602                 }
603
604                 protected virtual void InitializeItem (DataListItem item)
605                 {
606                         ITemplate t = null;
607                         
608                         switch (item.ItemType) {
609                         case ListItemType.Header:
610                                 t = HeaderTemplate;
611                                 break;
612                         case ListItemType.Footer:
613                                 t = FooterTemplate;
614                                 break;  
615                         case ListItemType.Separator:
616                                 t = SeparatorTemplate;
617                                 break;
618                         case ListItemType.Item:
619                         case ListItemType.AlternatingItem:
620                         case ListItemType.SelectedItem:
621                         case ListItemType.EditItem:
622                                 int index = item.ItemIndex;
623                                 if (SelectedIndex == index)
624                                         t = SelectedItemTemplate;
625                                 else if (EditItemIndex == index)
626                                         t = EditItemTemplate;
627                                 else if (((index & 1) == 0) || (alternatingItemTemplate == null))
628                                         t = ItemTemplate;
629                                 else
630                                         t = alternatingItemTemplate;
631                                 break;
632                         }
633
634                         if (t != null)
635                                 t.InstantiateIn (item);
636                 }
637
638                 protected override void LoadViewState (object savedState)
639                 {
640                         object[] state = (object[]) savedState;
641                         base.LoadViewState (state [0]);
642                         if (state [1] != null)
643                                 ItemStyle.LoadViewState (state [1]);
644                         if (state [2] != null)
645                                 SelectedItemStyle.LoadViewState (state [2]);
646                         if (state [3] != null)
647                                 AlternatingItemStyle.LoadViewState (state [3]);
648                         if (state [4] != null)
649                                 EditItemStyle.LoadViewState (state [4]);
650                         if (state [5] != null)
651                                 SeparatorStyle.LoadViewState (state [5]);
652                         if (state [6] != null)
653                                 HeaderStyle.LoadViewState (state [6]);
654                         if (state [7] != null)
655                                 FooterStyle.LoadViewState (state [7]);
656                 }
657
658                 protected override bool OnBubbleEvent (object source, EventArgs e)
659                 {
660                         DataListCommandEventArgs dlca = (e as DataListCommandEventArgs);
661                         if (dlca == null)
662                                 return false;
663
664                         string cn = dlca.CommandName;
665                         CultureInfo inv = CultureInfo.InvariantCulture;
666
667                         OnItemCommand (dlca);
668                         if (String.Compare (cn, CancelCommandName, true, inv) == 0) {
669                                 OnCancelCommand (dlca);
670                                 return true;
671                         } else if (String.Compare (cn, DeleteCommandName, true, inv) == 0) {
672                                 OnDeleteCommand (dlca);
673                                 return true;
674                         } else if (String.Compare (cn, EditCommandName, true, inv) == 0) {
675                                 OnEditCommand (dlca);
676                                 return true;
677                         } else if (String.Compare (cn, SelectCommandName, true, inv) == 0) {
678                                 OnSelectedIndexChanged (dlca);
679                                 return true;
680                         } else if (String.Compare (cn, UpdateCommandName, true, inv) == 0) {
681                                 OnUpdateCommand (dlca);
682                                 return true;
683                         }
684                         return false;
685                 }
686
687                 protected virtual void OnCancelCommand (DataListCommandEventArgs e)
688                 {
689                         DataListCommandEventHandler cancelCommand = (DataListCommandEventHandler) Events [cancelCommandEvent];
690                         if (cancelCommand != null)
691                                 cancelCommand (this, e);
692                 }
693
694                 protected virtual void OnDeleteCommand (DataListCommandEventArgs e)
695                 {
696                         DataListCommandEventHandler deleteCommand = (DataListCommandEventHandler) Events [deleteCommandEvent];
697                         if (deleteCommand != null)
698                                 deleteCommand (this, e);
699                 }
700
701                 protected virtual void OnEditCommand (DataListCommandEventArgs e)
702                 {
703                         DataListCommandEventHandler editCommand = (DataListCommandEventHandler) Events [editCommandEvent];
704                         if (editCommand != null)
705                                 editCommand (this, e);
706                 }
707 #if NET_2_0
708                 protected internal override void OnInit (EventArgs e)
709                 {
710                         // EditItemIndex and SelectedIndex now use the Control State (i.e not the View State)
711                         Page.RegisterRequiresControlState (this);
712                         base.OnInit (e);
713                 }
714 #endif
715                 protected virtual void OnItemCommand (DataListCommandEventArgs e)
716                 {
717                         DataListCommandEventHandler itemCommand = (DataListCommandEventHandler) Events [itemCommandEvent];
718                         if (itemCommand != null)
719                                 itemCommand (this, e);
720                 }
721
722                 protected virtual void OnItemCreated (DataListItemEventArgs e)
723                 {
724                         DataListItemEventHandler itemCreated = (DataListItemEventHandler) Events [itemCreatedEvent];
725                         if (itemCreated != null)
726                                 itemCreated (this, e);
727                 }
728
729                 protected virtual void OnItemDataBound (DataListItemEventArgs e)
730                 {
731                         DataListItemEventHandler itemDataBound = (DataListItemEventHandler) Events [itemDataBoundEvent];
732                         if (itemDataBound != null)
733                                 itemDataBound (this, e);
734                 }
735
736                 protected virtual void OnUpdateCommand (DataListCommandEventArgs e)
737                 {
738                         DataListCommandEventHandler updateCommand = (DataListCommandEventHandler) Events [updateCommandEvent];
739                         if (updateCommand != null)
740                                 updateCommand (this, e);
741                 }
742
743                 void ApplyControlStyle (Control ctrl, Style style)
744                 {
745                         if (style == null || false == ctrl.HasControls ())
746                                 return;
747
748                         foreach (Control c in ctrl.Controls) {
749                                 if (c is Table) {
750                                         Table tbl = (Table) c;
751                                         foreach (TableRow row in tbl.Rows)
752                                                 row.MergeStyle (style);
753                                 }
754                         }
755                 }
756
757                 protected override void PrepareControlHierarchy ()
758                 {
759                         if (!HasControls () || Controls.Count == 0)
760                                 return; // No one called CreateControlHierarchy() with DataSource != null
761
762                         Style alt = null;
763                         foreach (DataListItem item in Controls) {
764                                 switch (item.ItemType) {
765                                 case ListItemType.Item:
766                                         item.MergeStyle (itemStyle);
767                                         ApplyControlStyle (item, itemStyle);
768                                         break;
769                                 case ListItemType.AlternatingItem:
770                                         if (alt == null) {
771                                                 if (alternatingItemStyle != null) {
772                                                         alt = new Style ();
773                                                         alt.CopyFrom (itemStyle);
774                                                         alt.CopyFrom (alternatingItemStyle);
775                                                 } else {
776                                                         alt = itemStyle;
777                                                 }
778                                         }
779
780                                         item.MergeStyle (alt);
781                                         ApplyControlStyle (item, alt);
782                                         break;
783                                 case ListItemType.EditItem:
784                                         item.MergeStyle (editItemStyle);
785                                         ApplyControlStyle (item, editItemStyle);
786                                         break;
787                                 case ListItemType.Footer:
788                                         if (!ShowFooter) {
789                                                 item.Visible = false;
790                                                 break;
791                                         }
792                                         if (footerStyle != null) {
793                                                 item.MergeStyle (footerStyle);
794                                                 ApplyControlStyle (item, footerStyle);
795                                         }
796                                         break;
797                                 case ListItemType.Header:
798                                         if (!ShowHeader) {
799                                                 item.Visible = false;
800                                                 break;
801                                         }
802                                         if (headerStyle != null) {
803                                                 item.MergeStyle (headerStyle);
804                                                 ApplyControlStyle (item, headerStyle);
805                                         }
806                                         break;
807                                 case ListItemType.SelectedItem:
808                                         if (selectedItemStyle != null) {
809                                                 item.MergeStyle (selectedItemStyle);
810                                                 ApplyControlStyle (item, selectedItemStyle);
811                                         } else {
812                                                 item.MergeStyle (itemStyle);
813                                                 ApplyControlStyle (item, itemStyle);
814                                         }
815                                         break;
816                                 case ListItemType.Separator:
817                                         ApplyControlStyle (item, separatorStyle);
818                                         break;
819                                 }
820                         }
821                 }
822
823 #if NET_2_0
824                 protected internal
825 #else           
826                 protected
827 #endif          
828                 override void RenderContents (HtmlTextWriter writer)
829                 {
830                         RepeatInfo ri = new RepeatInfo ();
831                         ri.RepeatColumns = RepeatColumns;
832                         ri.RepeatDirection = RepeatDirection;
833                         ri.RepeatLayout = RepeatLayout;
834 /*
835 // debugging stuff that I prefer to keep for a while
836 Console.WriteLine ("RepeatColumns {0}", ri.RepeatColumns);
837 Console.WriteLine ("RepeatDirection {0}", ri.RepeatDirection);
838 Console.WriteLine ("RepeatLayout {0}", ri.RepeatLayout);
839 Console.WriteLine ("OuterTableImplied {0}", ExtractTemplateRows);
840 Console.WriteLine ("IRepeatInfoUser.HasFooter {0}", (ShowFooter && (footerTemplate != null)));
841 Console.WriteLine ("IRepeatInfoUser.HasHeader {0}", (ShowHeader && (headerTemplate != null)));
842 Console.WriteLine ("IRepeatInfoUser.HasSeparators {0}", (separatorTemplate != null));
843 Console.WriteLine ("IRepeatInfoUser.RepeatedItemCount {0}", Items.Count);
844 for (int i=0; i < Items.Count; i++) {
845         DataListItem dli = Items [i];
846         Console.WriteLine ("{0}: Index {1}, Type {2}", i, dli.ItemIndex, dli.ItemType);
847 }
848 */
849                         bool extract = ExtractTemplateRows;
850                         if (extract) {
851                                 ri.OuterTableImplied = true;
852                                 writer.AddAttribute (HtmlTextWriterAttribute.Id, ClientID);
853                                 if (ControlStyleCreated) {
854                                         ControlStyle.AddAttributesToRender (writer);
855                                 }
856                                 writer.RenderBeginTag (HtmlTextWriterTag.Table);
857                                 ri.RenderRepeater (writer, this, ControlStyle, this);
858                                 writer.RenderEndTag ();
859                         } else {
860                                 ri.RenderRepeater (writer, this, ControlStyle, this);
861                         }
862                 }
863
864                 protected override object SaveViewState ()
865                 {
866 #if NET_2_0
867                         object[] state = new object [9];
868                         // FIXME: what's new in slot #0 ?
869                         state[8] = base.SaveViewState ();
870 #else
871                         object[] state = new object [8];
872                         state[0] = base.SaveViewState ();
873 #endif
874                         if (itemStyle != null)
875                                 state [1] = itemStyle.SaveViewState ();
876                         if (selectedItemStyle != null)
877                                 state [2] = selectedItemStyle.SaveViewState ();
878                         if (alternatingItemStyle != null)
879                                 state [3] = alternatingItemStyle.SaveViewState ();
880                         if (editItemStyle != null)
881                                 state [4] = editItemStyle.SaveViewState ();
882                         if (separatorStyle != null)
883                                 state [5] = separatorStyle.SaveViewState ();
884                         if (headerStyle != null)
885                                 state [6] = headerStyle.SaveViewState ();
886                         if (footerStyle != null)
887                                 state [7] = footerStyle.SaveViewState ();
888                         return state;
889                 }
890
891                 protected override void TrackViewState ()
892                 {
893                         base.TrackViewState ();
894                         if (alternatingItemStyle != null)
895                                 alternatingItemStyle.TrackViewState ();
896                         if (editItemStyle != null)
897                                 editItemStyle.TrackViewState ();
898                         if (footerStyle != null)
899                                 footerStyle.TrackViewState ();
900                         if (headerStyle != null)
901                                 headerStyle.TrackViewState ();
902                         if (itemStyle != null)
903                                 itemStyle.TrackViewState ();
904                         if (selectedItemStyle != null)
905                                 selectedItemStyle.TrackViewState ();
906                         if (separatorStyle != null)
907                                 separatorStyle.TrackViewState ();
908                 }
909
910
911                 [WebSysDescription ("")]
912                 [WebCategory ("Action")]
913                 public event DataListCommandEventHandler CancelCommand {
914                         add { Events.AddHandler (cancelCommandEvent, value); }
915                         remove { Events.RemoveHandler (cancelCommandEvent, value); }
916                 }
917
918                 [WebSysDescription ("")]
919                 [WebCategory ("Action")]
920                 public event DataListCommandEventHandler DeleteCommand {
921                         add { Events.AddHandler (deleteCommandEvent, value); }
922                         remove { Events.RemoveHandler (deleteCommandEvent, value); }
923                 }
924
925                 [WebSysDescription ("")]
926                 [WebCategory ("Action")]
927                 public event DataListCommandEventHandler EditCommand {
928                         add { Events.AddHandler (editCommandEvent, value); }
929                         remove { Events.RemoveHandler (editCommandEvent, value); }
930                 }
931
932                 [WebSysDescription ("")]
933                 [WebCategory ("Action")]
934                 public event DataListCommandEventHandler ItemCommand {
935                         add { Events.AddHandler (itemCommandEvent, value); }
936                         remove { Events.RemoveHandler (itemCommandEvent, value); }
937                 }
938
939                 [WebSysDescription ("")]
940                 [WebCategory ("Action")]
941                 public event DataListItemEventHandler ItemCreated {
942                         add { Events.AddHandler (itemCreatedEvent, value); }
943                         remove { Events.RemoveHandler (itemCreatedEvent, value); }
944                 }
945
946                 [WebSysDescription ("")]
947                 [WebCategory ("Action")]
948                 public event DataListItemEventHandler ItemDataBound {
949                         add { Events.AddHandler (itemDataBoundEvent, value); }
950                         remove { Events.RemoveHandler (itemDataBoundEvent, value); }
951                 }
952
953                 [WebSysDescription ("")]
954                 [WebCategory ("Action")]
955                 public event DataListCommandEventHandler UpdateCommand {
956                         add { Events.AddHandler (updateCommandEvent, value); }
957                         remove { Events.RemoveHandler (updateCommandEvent, value); }
958                 }
959
960
961                 // IRepeatInfoUser support
962
963                 bool IRepeatInfoUser.HasFooter {
964                         get { return (ShowFooter && (footerTemplate != null)); }
965                 }
966
967                 bool IRepeatInfoUser.HasHeader {
968                         get { return (ShowHeader && (headerTemplate != null)); }
969                 }
970                 
971                 bool IRepeatInfoUser.HasSeparators {
972                         get { return (separatorTemplate != null); }
973                 }
974
975                 // don't include header, footer and separators in the count
976                 int IRepeatInfoUser.RepeatedItemCount {
977                         get {
978                                 if (idx == -1) {
979                                         object o = ViewState ["Items"];
980                                         idx = (o == null) ? 0 : (int) o;
981                                 }
982                                 return idx;
983                         }
984                 }
985
986                 Style IRepeatInfoUser.GetItemStyle (ListItemType itemType, int repeatIndex)
987                 {
988                         DataListItem item = null;
989                         switch (itemType) {
990                         case ListItemType.Header:
991                         case ListItemType.Footer:
992                                 if (repeatIndex >= 0 && (!HasControls () || repeatIndex >= Controls.Count))
993                                         throw new ArgumentOutOfRangeException ();
994
995                                 item = FindFirstItem (itemType);
996                                 break;
997                         case ListItemType.Item:
998                         case ListItemType.AlternatingItem:
999                         case ListItemType.SelectedItem:
1000                         case ListItemType.EditItem:
1001                                 if (repeatIndex >= 0 && (!HasControls () || repeatIndex >= Controls.Count))
1002                                         throw new ArgumentOutOfRangeException ();
1003
1004                                 item = FindBestItem (repeatIndex);
1005                                 break;
1006                         case ListItemType.Separator:
1007                                 if (repeatIndex >= 0 && (!HasControls () || repeatIndex >= Controls.Count))
1008                                         throw new ArgumentOutOfRangeException ();
1009
1010                                 item = FindSpecificItem (itemType, repeatIndex);
1011                                 break;
1012                         default:
1013                                 item = null;
1014                                 break;
1015                         }
1016
1017                         if (item == null || item.ControlStyleCreated == false)
1018                                 return null;
1019
1020                         return item.ControlStyle;
1021                 }
1022
1023                 // Header and Footer don't have a "real" index (-1)
1024                 private DataListItem FindFirstItem (ListItemType itemType)
1025                 {
1026                         for (int i = 0; i < Controls.Count; i++) {
1027                                 DataListItem item = (Controls [i] as DataListItem);
1028                                 if ((item != null) && (item.ItemType == itemType))
1029                                         return item;
1030                         }
1031                         return null;
1032                 }
1033
1034                 // Both Type and Index must match (e.g. Separator)
1035                 private DataListItem FindSpecificItem (ListItemType itemType, int repeatIndex)
1036                 {
1037                         for (int i = 0; i < Controls.Count; i++) {
1038                                 DataListItem item = (Controls [i] as DataListItem);
1039                                 if ((item != null) && (item.ItemType == itemType) && (item.ItemIndex == repeatIndex))
1040                                         return item;
1041                         }
1042                         return null;
1043                 }
1044
1045                 // we get call for Item even for AlternatingItem :(
1046                 private DataListItem FindBestItem (int repeatIndex)
1047                 {
1048                         for (int i = 0; i < Controls.Count; i++) {
1049                                 DataListItem item = (Controls [i] as DataListItem);
1050                                 if ((item != null) && (item.ItemIndex == repeatIndex)) {
1051                                         switch (item.ItemType) {
1052                                         case ListItemType.Item:
1053                                         case ListItemType.AlternatingItem:
1054                                         case ListItemType.SelectedItem:
1055                                         case ListItemType.EditItem:
1056                                                 return item;
1057                                         default:
1058                                                 return null;
1059                                         }
1060                                 }
1061                         }
1062                         return null;
1063                 }
1064
1065                 void IRepeatInfoUser.RenderItem (ListItemType itemType, int repeatIndex, RepeatInfo repeatInfo, HtmlTextWriter writer)
1066                 {
1067                         // if possible take the easy way out...
1068                         if (!HasControls ())
1069                                 return;
1070
1071                         DataListItem item = null;
1072                         switch (itemType) {
1073                         case ListItemType.Header:
1074                         case ListItemType.Footer:
1075                                 item = FindFirstItem (itemType);
1076                                 break;
1077                         case ListItemType.Item:
1078                         case ListItemType.AlternatingItem:
1079                         case ListItemType.SelectedItem:
1080                         case ListItemType.EditItem:
1081                                 item = FindBestItem (repeatIndex);
1082                                 break;
1083                         case ListItemType.Separator:
1084                                 item = FindSpecificItem (itemType, repeatIndex);
1085                                 break;
1086                         }
1087
1088                         if (item != null) {
1089                                 bool extract = ExtractTemplateRows;
1090                                 bool table = (RepeatLayout == RepeatLayout.Table);
1091                                 if (!table || extract) {
1092                                         // sadly RepeatInfo doesn't support Style for RepeatLayout.Flow
1093                                         Style s = (this as IRepeatInfoUser).GetItemStyle (itemType, repeatIndex);
1094                                         if (s != null)
1095                                                 item.ControlStyle.CopyFrom (s);
1096                                 }
1097 //Console.WriteLine ("RenderItem #{0} type {1}", repeatIndex, itemType);
1098                                 item.RenderItem (writer, extract, table);
1099                         } else {
1100 //Console.WriteLine ("Couldn't find #{0} type {1} out of {2} items / {3} controls", repeatIndex, itemType, Items.Count, Controls.Count);
1101                         }
1102                 }
1103         }
1104 }