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