merge -r 98047:98048
[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                 private static readonly object SelectedIndexChangedEvent = new object ();
58 #if NET_2_0
59                 private static readonly object TextChangedEvent = new object ();
60 #endif
61
62                 private 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                 private 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
394 #if !NET_2_0
395                         IEnumerable list = DataSourceResolver.ResolveDataSource (DataSource, DataMember);
396 #else
397                         IEnumerable list = GetData ().ExecuteSelect (DataSourceSelectArguments.Empty);
398 #endif
399                         PerformDataBinding (list);
400
401                 }
402
403 #if NET_2_0
404                 protected internal
405 #else           
406                 protected
407 #endif          
408                 override void OnPreRender (EventArgs e)
409                 {
410                         base.OnPreRender (e);
411 #if NET_2_0
412                         if (Page != null && Enabled)
413                                 Page.RegisterEnabledControl (this);
414 #endif
415                 }
416
417 #if NET_2_0
418                 protected virtual void OnTextChanged (EventArgs e)
419                 {
420                         EventHandler handler = (EventHandler) Events [TextChangedEvent];
421                         if (handler != null)
422                                 handler (this, e);
423                 }
424 #endif          
425
426 #if NET_2_0
427                 protected internal override
428 #endif
429                 void PerformDataBinding (IEnumerable dataSource)
430                 {
431                         if (dataSource == null)
432 #if NET_2_0
433                                 goto setselected;
434 #else
435                                 return;
436 #endif
437 #if NET_2_0
438                         if (!AppendDataBoundItems)
439 #endif
440                                 Items.Clear ();
441
442                         string format = DataTextFormatString;
443                         if (format == "")
444                                 format = null;
445
446                         string text_field = DataTextField;
447                         string value_field = DataValueField;
448                         ListItemCollection coll = Items;
449                         foreach (object container in dataSource) {
450                                 string text;
451                                 string val;
452
453                                 text = val = null;
454                                 if (text_field != "") {
455                                         text = DataBinder.GetPropertyValue (container, text_field, format);
456                                 }
457
458                                 if (value_field != "") {
459                                         val = DataBinder.GetPropertyValue (container, value_field).ToString ();
460                                 }
461                                 else if (text_field == "") {
462                                         text = val = container.ToString ();
463                                         if (format != null)
464                                                 text = String.Format (format, container);
465                                 }
466                                 else if (text != null) {
467                                         val = text;
468                                 }
469
470                                 if (text == null)
471                                         text = val;
472
473                                 coll.Add (new ListItem (text, val));
474                         }
475
476 #if NET_2_0
477                 setselected:
478                         if (!String.IsNullOrEmpty (_selectedValue)) {
479                                 if (!SetSelectedValue (_selectedValue))
480                                         throw new ArgumentOutOfRangeException ("value", String.Format ("'{0}' has a SelectedValue which is invalid because it does not exist in the list of items.", ID));
481                                 if (_selectedIndex >= 0 && _selectedIndex != SelectedIndex)
482                                         throw new ArgumentException ("SelectedIndex and SelectedValue are mutually exclusive.");
483                         }
484                         else if (_selectedIndex >= 0) {
485                                 SelectedIndex = _selectedIndex;
486                         }
487 #else
488                         if (saved_selected_value != null) {
489                                 SelectedValue = saved_selected_value;
490                                 if (saved_selected_index != -2 && saved_selected_index != SelectedIndex)
491                                         throw new ArgumentException ("SelectedIndex and SelectedValue are mutually exclusive.");
492                         }
493                         else if (saved_selected_index != -2) {
494                                 SelectedIndex = saved_selected_index;
495                                 // No need to check saved_selected_value here, as it's done before.
496                         }
497 #endif
498                 }
499
500 #if NET_2_0
501                 [MonoTODO ("why override?")]
502                 protected override void PerformSelect ()
503                 {
504                         OnDataBinding (EventArgs.Empty);
505                         RequiresDataBinding = false;
506                         MarkAsDataBound ();
507                         OnDataBound (EventArgs.Empty);
508                 }
509
510                 protected internal override void RenderContents (HtmlTextWriter writer)
511                 {
512                         bool selected = false;
513                         bool havePage = Page != null;
514                         for (int i = 0; i < Items.Count; i++) {
515                                 ListItem item = Items [i];
516                                 if (havePage)
517                                         Page.ClientScript.RegisterForEventValidation (this.UniqueID, item.Value.ToString ());
518                                 writer.WriteBeginTag ("option");
519                                 if (item.Selected) {
520                                         if (selected)
521                                                 VerifyMultiSelect ();
522                                         writer.WriteAttribute ("selected", "selected", false);
523                                         selected = true;
524                                 }
525                                 writer.WriteAttribute ("value", item.Value, true);
526
527                                 if (item.HasAttributes)
528                                         item.Attributes.Render (writer);
529
530                                 writer.Write (">");
531                                 string encoded = HttpUtility.HtmlEncode (item.Text);
532                                 writer.Write (encoded);
533                                 writer.WriteEndTag ("option");
534                                 writer.WriteLine ();
535                         }
536                 }
537
538 #endif          
539
540                 internal ArrayList GetSelectedIndicesInternal ()
541                 {
542                         ArrayList selected = null;
543                         int count;
544                         
545                         if (items != null && (count = items.Count) > 0) {
546                                 selected = new ArrayList ();
547                                 for (int i = 0; i < count; i++) {
548                                         if (items [i].Selected)
549                                                 selected.Add (i);
550                                 }
551                         }
552                         return selected;
553                 }
554
555                 protected override object SaveViewState ()
556                 {
557                         object baseState = null;
558                         object itemsState = null;
559
560                         baseState = base.SaveViewState ();
561
562                         IStateManager manager = items as IStateManager;
563                         if (manager != null)
564                                 itemsState = manager.SaveViewState ();
565
566                         if (baseState == null && itemsState == null)
567                                 return null;
568
569                         return new Pair (baseState, itemsState);
570                 }
571
572                 protected override void LoadViewState (object savedState)
573                 {
574                         object baseState = null;
575                         object itemsState = null;
576
577                         Pair pair = savedState as Pair;
578                         if (pair != null) {
579                                 baseState = pair.First;
580                                 itemsState = pair.Second;
581                         }
582
583                         base.LoadViewState (baseState);
584
585                         if (itemsState != null) {
586                                 IStateManager manager = Items as IStateManager;
587                                 manager.LoadViewState (itemsState);
588                         }
589                 }
590
591 #if NET_2_0
592                 [MonoTODO ("Not implemented")]
593                 protected void SetPostDataSelection (int selectedIndex)
594                 {
595                         throw new NotImplementedException ();
596                 }
597 #endif          
598
599                 protected override void TrackViewState ()
600                 {
601                         base.TrackViewState ();
602                         IStateManager manager = items as IStateManager;
603                         if (manager != null)
604                                 manager.TrackViewState ();
605                 }
606
607                 protected virtual void OnSelectedIndexChanged (EventArgs e)
608                 {
609                         EventHandler handler = (EventHandler) Events [SelectedIndexChangedEvent];
610                         if (handler != null)
611                                 handler (this, e);
612                 }
613
614 #if NET_2_0             
615                 protected internal virtual void VerifyMultiSelect ()
616                 {
617             throw new HttpException("Multi select is not supported");
618                 }
619 #endif          
620
621                 [WebSysDescription ("")]
622                 [WebCategory ("Action")]
623                 public event EventHandler SelectedIndexChanged {
624                         add { Events.AddHandler (SelectedIndexChangedEvent, value); }
625                         remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
626                 }
627
628 #if NET_2_0
629                 /* sealed in the docs */
630                 public event EventHandler TextChanged {
631                         add {
632                                 Events.AddHandler (TextChangedEvent, value);
633                         }
634                         remove {
635                                 Events.RemoveHandler (TextChangedEvent, value);
636                         }
637                 }
638                 
639                 
640                 [Themeable (false)]
641                 [DefaultValue (false)]
642                 [WebSysDescription ("")]
643                 [WebCategory ("Behavior")]
644                 public virtual bool CausesValidation {
645                         get {
646                                 return ViewState.GetBool ("CausesValidation", false);
647                         }
648
649                         set {
650                                 ViewState ["CausesValidation"] = value;
651                         }
652                 }
653
654                 [Themeable (false)]
655                 [DefaultValue ("")]
656                 [WebSysDescription ("")]
657                 [WebCategoryAttribute ("Behavior")]
658                 public virtual string ValidationGroup {
659                         get {
660                                 return ViewState.GetString ("ValidationGroup", "");
661                         }
662                         set {
663                                 ViewState ["ValidationGroup"] = value;
664                         }
665                 }
666
667         
668 #endif
669         }
670 }
671
672
673
674
675