2006-04-11 Lluis Sanchez <lluis@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / ListControl.cs
1 //
2 // System.Web.UI.WebControls.ListControl.cs
3 //
4 // Authors:
5 //      Jackson Harper (jackson@ximian.com)
6 //
7 // (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;
30 using System.Drawing;
31 using System.Web.Util;
32 using System.Collections;
33 using System.Globalization;
34 using System.ComponentModel;
35 using System.Collections.Specialized;
36
37 namespace System.Web.UI.WebControls {
38
39         [DataBindingHandler("System.Web.UI.Design.WebControls.ListControlDataBindingHandler, " + Consts.AssemblySystem_Design)]
40         [DefaultEventAttribute ("SelectedIndexChanged")]
41 #if !NET_2_0
42         [DefaultPropertyAttribute ("DataSource")]
43 #endif
44         [Designer("System.Web.UI.Design.WebControls.ListControlDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
45 #if NET_2_0
46         [ControlValueProperty ("SelectedValue", null)]
47         [ParseChildrenAttribute (true, "Items", ChildControlType = typeof (Control))]
48 #else
49         [ParseChildrenAttribute (true, "Items")]
50 #endif  
51         public abstract class ListControl :
52 #if NET_2_0
53         DataBoundControl, IEditableTextControl, ITextControl
54 #else           
55         WebControl
56 #endif
57         {
58
59                 private static readonly object SelectedIndexChangedEvent = new object ();
60 #if NET_2_0
61                 private static readonly object TextChangedEvent = new object ();
62 #endif
63
64                 private ListItemCollection items;
65                 int saved_selected_index = -2;
66                 string saved_selected_value;
67                 
68                 public ListControl () : base (HtmlTextWriterTag.Select)
69                 {
70                 }
71
72 #if NET_2_0
73                 [DefaultValue (false)]
74                 [Themeable (false)]
75                 [MonoTODO]
76                 [WebSysDescription ("")]
77                 [WebCategory ("Behavior")]
78                 public virtual bool AppendDataBoundItems
79                 {
80                         get {
81                                 return ViewState.GetBool ("AppendDataBoundItems", false);
82                         }
83                         set {
84                                 ViewState ["AppendDataBoundItems"] = value;
85                         }
86                 }
87 #endif          
88                 
89 #if NET_2_0
90                 [Themeable (false)]
91 #endif
92                 [DefaultValue(false)]
93                 [WebSysDescription ("")]
94                 [WebCategory ("Behavior")]
95                 public virtual bool AutoPostBack {
96                         get { return ViewState.GetBool ("AutoPostBack", false); }
97                         set { ViewState ["AutoPostBack"] = value; }
98                 }
99
100 #if ONLY_1_1
101                 [DefaultValue("")]
102                 [WebSysDescription ("")]
103                 [WebCategory ("Data")]
104                 public virtual string DataMember {
105                         get { return ViewState.GetString ("DataMember", String.Empty); }
106                         set { ViewState ["DataMember"] = value; }
107                 }
108
109                 private object data_source;
110
111                 [Bindable(true)]
112                 [DefaultValue(null)]
113                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
114                 [WebSysDescription ("")]
115                 [WebCategory ("Data")]
116                 public virtual object DataSource {
117                         get { return data_source; }
118                         set { 
119                                 if(value == null || value is IListSource || value is IEnumerable) { 
120                                         data_source = value;
121                                         return;
122                                 }
123                                 throw new ArgumentException("Invalid DataSource Type");
124                         }
125                 }
126 #endif          
127
128 #if NET_2_0
129                 [Themeable (false)]
130 #endif          
131                 [DefaultValue("")]
132                 [WebSysDescription ("")]
133                 [WebCategory ("Data")]
134                 public virtual string DataTextField {
135                         get { return ViewState.GetString ("DataTextField", String.Empty); }
136                         set { ViewState ["DataTextField"] = value; }
137                 }
138
139 #if NET_2_0
140                 [Themeable (false)]
141 #endif          
142                 [DefaultValue("")]
143                 [WebSysDescription ("")]
144                 [WebCategory ("Data")]
145                 public virtual string DataTextFormatString {
146                         get { return ViewState.GetString ("DataTextFormatString", String.Empty); }
147                         set { ViewState ["DataTextFormatString"] = value; }
148                 }
149
150 #if NET_2_0
151                 [Themeable (false)]
152 #endif          
153                 [DefaultValue("")]
154                 [WebSysDescription ("")]
155                 [WebCategory ("Data")]
156                 public virtual string DataValueField {
157                         get { return ViewState.GetString ("DataValueField", String.Empty); }
158                         set { ViewState ["DataValueField"] = value; }
159                 }
160
161 #if NET_2_0
162                 [Editor ("System.Web.UI.Design.WebControls.ListItemsCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
163 #endif          
164                 [DefaultValue(null)]
165                 [MergableProperty(false)]
166                 [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
167                 [WebSysDescription ("")]
168                 [WebCategory ("Misc")]
169                 public virtual ListItemCollection Items {
170                         get {
171                                 if (items == null)
172                                         items = new ListItemCollection ();
173                                 return items;
174                         }
175                 }
176
177                 // I can't find this info stored in the viewstate anywhere
178                 // so it must be calculated on the fly.
179                 [Bindable(true)]
180                 [Browsable(false)]
181                 [DefaultValue(0)]
182                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
183 #if NET_2_0
184                 [Themeable (false)]
185 #endif          
186                 [WebSysDescription ("")]
187                 [WebCategory ("Misc")]
188                 public virtual int SelectedIndex {
189                         get {
190                                 if (items == null)
191                                         return -1;
192                                 for (int i = 0; i < items.Count; i++) {
193                                         if (items [i].Selected)
194                                                 return i;
195                                 }
196                                 return -1;
197                         }
198                         set {
199                                 if (items == null || items.Count == 0) {
200                                         // This will happen when assigning this property
201                                         // before DataBind () is called on the control.
202                                         saved_selected_index = value;
203                                         return;
204                                 }
205
206                                 if (value < -1 || value >= Items.Count)
207                                         throw new ArgumentOutOfRangeException ("value");
208
209                                 ClearSelection ();
210                                 if (value == -1)
211                                         return;
212
213                                 items [value].Selected = true;
214
215                                 /* you'd think this would be called, but noooo */
216                                 //OnSelectedIndexChanged (EventArgs.Empty);
217                         }
218                 }
219
220                 [Browsable(false)]
221                 [DefaultValue(null)]
222                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
223                 [WebSysDescription ("")]
224                 [WebCategory ("Misc")]
225                 public virtual ListItem SelectedItem {
226                         get {
227                                 int si = SelectedIndex;
228                                 if (si == -1)
229                                         return null;
230                                 return Items [si];
231                         }
232                 }
233
234 #if NET_2_0
235                 [Bindable(true, BindingDirection.TwoWay)]
236                 [Themeable (false)]
237 #else           
238                 [Bindable(true)]
239 #endif          
240                 [Browsable(false)]
241                 [DefaultValue("")]
242                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
243                 [WebSysDescription ("")]
244                 [WebCategory ("Misc")]
245                 public virtual string SelectedValue {
246                         get {
247                                 int si = SelectedIndex;
248                                 if (si == -1)
249                                         return String.Empty;
250                                 return Items [si].Value;
251                         }
252                         set {
253                                 ClearSelection ();
254                                 if (items == null || items.Count == 0) {
255                                         // This will happen when assigning this property
256                                         // before DataBind () is called on the control.
257                                         saved_selected_value = value;
258                                         return;
259                                 }
260
261                                 int count = Items.Count;
262                                 ListItemCollection coll = Items;
263                                 bool thr = true;
264                                 for (int i = 0; i < count; i++) {
265                                         if (coll [i].Value == value) {
266                                                 coll [i].Selected = true;
267                                                 thr = false;
268                                         }
269                                 }
270
271                                 if (thr) {
272                                         string msg = String.Format ("Argument value is out of range: {0}", value);
273                                         throw new ArgumentOutOfRangeException (msg);
274                                 }
275                         }
276                 }
277
278 #if NET_2_0
279                 [Themeable (false)]
280                 [DefaultValue ("")]
281                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
282                 [Browsable (false)]
283                 [MonoTODO]
284                 [WebSysDescription ("")]
285                 [WebCategoryAttribute ("Behavior")]
286                 public virtual string Text {
287                         get {
288                                 return SelectedValue;
289                         }
290                         set {
291                                 SelectedValue = value;
292                                 /* you'd think this would be called, but noooo */
293                                 //OnTextChanged (EventArgs.Empty);
294                         }
295                 }
296
297 #if HAVE_CONTROL_ADAPTERS
298                 protected virtual new
299 #else           
300                 protected override
301 #endif
302                 HtmlTextWriterTag TagKey
303                 {
304                         get {
305                                 return HtmlTextWriterTag.Select;
306                         }
307                 }
308
309                 protected override void AddAttributesToRender (HtmlTextWriter w)
310                 {
311                         base.AddAttributesToRender (w);
312                 }
313                 
314 #endif          
315
316                 public virtual void ClearSelection ()
317                 {
318                         if (items == null)
319                                 return;
320
321                         int count = Items.Count;
322                         for (int i = 0; i<count; i++)
323                                 items [i].Selected = false;
324                 }
325
326 #if NET_2_0
327                 protected internal override void LoadControlState (object savedState)
328                 {
329                         object first = null;
330                         ArrayList indices = null;
331                         Pair pair = savedState as Pair;
332
333                         if (pair != null) {
334                                 first = pair.First;
335                                 indices = pair.Second as ArrayList;
336                         }
337
338                         base.LoadControlState (first);
339
340                         if (indices != null) {
341                                 int count = Items.Count;
342                                 foreach (int index in indices) {
343                                         if (index >= 0 && index < count)
344                                                 Items [index].Selected = true;
345                                 }
346                         }
347                 }
348 #endif          
349
350                 protected override void OnDataBinding (EventArgs e)
351                 {
352                         base.OnDataBinding (e);
353
354                         IEnumerable list = DataSourceResolver.ResolveDataSource (DataSource, DataMember);
355                         if (list == null)
356                                 return;
357
358 #if NET_2_0
359                         if (!AppendDataBoundItems)
360 #endif
361                                 Items.Clear();
362
363 #if !NET_2_0
364                         DoDataBinding (list);
365 #endif
366                         if (saved_selected_value != null) {
367                                 SelectedValue = saved_selected_value;
368                                 if (saved_selected_index != -2 && saved_selected_index != SelectedIndex)
369                                         throw new ArgumentException ("SelectedIndex and SelectedValue are mutually exclusive.");
370                         } else if (saved_selected_index != -2) {
371                                 SelectedIndex = saved_selected_index;
372                                 // No need to check saved_selected_value here, as it's done before.
373                         }
374                 }
375
376 #if NET_2_0
377                 protected internal override void OnInit (EventArgs e)
378                 {
379                         Page.RegisterRequiresControlState (this);
380                         base.OnInit (e);
381                 }
382 #endif          
383
384 #if NET_2_0
385                 protected internal
386 #else           
387                 protected
388 #endif          
389                 override void OnPreRender (EventArgs e)
390                 {
391                         base.OnPreRender (e);
392                 }
393
394                 void DoDataBinding (IEnumerable dataSource)
395                 {
396                         if (dataSource != null) {
397                                 string format = DataTextFormatString;
398                                 if (format == "")
399                                         format = null;
400
401                                 string text_field = DataTextField;
402                                 string value_field = DataValueField;
403                                 ListItemCollection coll = Items;
404                                 foreach (object container in dataSource) {
405                                         string text;
406                                         string val;
407
408                                         text = val = null;
409                                         if (text_field != "") {
410                                                 text = DataBinder.GetPropertyValue (container, text_field, format);
411                                         }
412
413                                         if (value_field != "") {
414                                                 val = DataBinder.GetPropertyValue (container, value_field).ToString ();
415                                         } else if (text_field == "") {
416                                                 text = val = container.ToString ();
417                                                 if (format != null)
418                                                         text = String.Format (format, container);
419                                         } else if (text != null) {
420                                                 val = text;
421                                         }
422
423                                         if (text == null)
424                                                 text = val;
425
426                                         coll.Add (new ListItem (text, val));
427                                 }
428                         }
429                 }
430
431 #if NET_2_0
432                 protected virtual void OnTextChanged (EventArgs e)
433                 {
434                         EventHandler handler = (EventHandler) Events [TextChangedEvent];
435                         if (handler != null)
436                                 handler (this, e);
437                 }
438
439                 protected internal override void PerformDataBinding (IEnumerable dataSource)
440                 {
441                         base.PerformDataBinding (dataSource);
442
443                         DoDataBinding (dataSource);
444                 }
445
446                 [MonoTODO ("why override?")]
447                 protected override void PerformSelect ()
448                 {
449                         base.PerformSelect ();
450                 }
451
452                 [MonoTODO]
453                 protected internal override void RenderContents (HtmlTextWriter w)
454                 {
455                         base.RenderContents (w);
456                 }
457
458                 protected internal override object SaveControlState ()
459                 {
460                         object first;
461                         ArrayList second;
462
463                         first = base.SaveControlState ();
464                         second = GetSelectedIndicesInternal ();
465                         if (second == null)
466                                 second = new ArrayList();
467
468                         return new Pair (first, second);
469                 }
470 #endif          
471
472                 internal ArrayList GetSelectedIndicesInternal ()
473                 {
474                         ArrayList selected = null;
475                         if (items != null) {
476                                 selected = new ArrayList ();
477                                 int count = Items.Count;
478                                 for (int i = 0; i < count; i++) {
479                                         if (items [i].Selected)
480                                                 selected.Add (i);
481                                 }
482                         }
483                         return selected;
484                 }
485
486                 protected override object SaveViewState ()
487                 {
488                         object first = null;
489                         object second = null;
490
491                         first = base.SaveViewState ();
492
493                         IStateManager manager = items as IStateManager;
494                         if (manager != null)
495                                 second = manager.SaveViewState ();
496
497 #if !NET_2_0
498                         ArrayList selected = GetSelectedIndicesInternal ();
499 #endif
500
501                         if (first == null && second == null
502 #if !NET_2_0
503                             && selected == null
504 #endif
505                             )
506                                 return null;
507
508 #if NET_2_0
509                         return new Pair (first, second);
510 #else
511                         return new Triplet (first, second, selected);
512 #endif
513                 }
514
515                 protected override void LoadViewState (object savedState)
516                 {
517                         object first = null;
518                         object second = null;
519 #if !NET_2_0
520                         ArrayList indices = null;
521 #endif
522
523 #if NET_2_0
524                         Pair pair = savedState as Pair;
525                         if (pair != null) {
526                                 first = pair.First;
527                                 second = pair.Second;
528                         }
529 #else
530                         Triplet triplet = savedState as Triplet;
531                         if (triplet != null) {
532                                 first = triplet.First;
533                                 second = triplet.Second;
534                                 indices = triplet.Third as ArrayList;
535                         }
536 #endif
537
538                         base.LoadViewState (first);
539
540                         if (second != null) {
541                                 IStateManager manager = Items as IStateManager;
542                                 manager.LoadViewState (second);
543                         }
544
545 #if !NET_2_0
546                         if (indices != null) {
547                                 foreach (int index in indices)
548                                         Items [index].Selected = true;
549                         }
550 #endif
551                 }
552
553 #if NET_2_0
554                 [MonoTODO]
555                 protected void SetPostDataSelection (int selectedIndex)
556                 {
557                         throw new NotImplementedException ();
558                 }
559 #endif          
560
561                 protected override void TrackViewState ()
562                 {
563                         base.TrackViewState ();
564                         IStateManager manager = items as IStateManager;
565                         if (manager != null)
566                                 manager.TrackViewState ();
567                 }
568
569                 protected virtual void OnSelectedIndexChanged (EventArgs e)
570                 {
571                         EventHandler handler = (EventHandler) Events [SelectedIndexChangedEvent];
572                         if (handler != null)
573                                 handler (this, e);
574                 }
575
576 #if NET_2_0             
577                 protected internal virtual void VerifyMultiSelect ()
578                 {
579                 }
580 #endif          
581
582                 [WebSysDescription ("")]
583                 [WebCategory ("Action")]
584                 public event EventHandler SelectedIndexChanged {
585                         add { Events.AddHandler (SelectedIndexChangedEvent, value); }
586                         remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
587                 }
588
589 #if NET_2_0
590                 /* sealed in the docs */
591                 public event EventHandler TextChanged {
592                         add {
593                                 Events.AddHandler (TextChangedEvent, value);
594                         }
595                         remove {
596                                 Events.RemoveHandler (TextChangedEvent, value);
597                         }
598                 }
599                 
600                 
601                 [MonoTODO]
602                 [Themeable (false)]
603                 [DefaultValue (false)]
604                 [WebSysDescription ("")]
605                 [WebCategory ("Behavior")]
606                 public virtual bool CausesValidation {
607                         get {
608                                 throw new NotImplementedException ();
609                         }
610                         set {
611                                 throw new NotImplementedException ();   
612                         }
613                 }
614
615                 [MonoTODO]
616                 [Themeable (false)]
617                 [DefaultValue ("")]
618                 [WebSysDescription ("")]
619                 [WebCategoryAttribute ("Behavior")]
620                 public virtual string ValidationGroup {
621                         get {
622                                 throw new NotImplementedException ();
623                         }
624                         set {
625                                 throw new NotImplementedException ();
626                         }
627                 }
628
629         
630 #endif
631         }
632 }
633