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