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