Flush (work in progress)
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / CheckBox.cs
1 //
2 // System.Web.UI.WebControls.CheckBox.cs
3 //
4 // Author:
5 //      Dick Porter  <dick@ximian.com>
6 //
7 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System.Collections;
30 using System.Collections.Specialized;
31 using System.ComponentModel;
32 using System.Globalization;
33 using System.Security.Permissions;
34 using System.Web.Util;
35
36 namespace System.Web.UI.WebControls {
37         // CAS
38         [AspNetHostingPermissionAttribute (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
39         [AspNetHostingPermissionAttribute (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
40         // attributes
41         [Designer ("System.Web.UI.Design.WebControls.CheckBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
42         [DataBindingHandler ("System.Web.UI.Design.TextDataBindingHandler, " + Consts.AssemblySystem_Design)]
43         [DefaultEvent ("CheckedChanged")]
44         [DefaultProperty ("Text")]
45 #if NET_2_0
46         [ControlValueProperty ("Checked", null)]
47         [SupportsEventValidation]
48 #endif          
49         public class CheckBox : WebControl, IPostBackDataHandler
50 #if NET_2_0
51         , ICheckBoxControl
52 #endif
53         {
54                 string render_type;
55                 AttributeCollection common_attrs;
56
57 #if NET_2_0
58                 AttributeCollection inputAttributes;
59                 StateBag inputAttributesState;
60                 AttributeCollection labelAttributes;
61                 StateBag labelAttributesState;
62 #endif
63                 
64                 public CheckBox () : base (HtmlTextWriterTag.Input)
65                 {
66                         render_type = "checkbox";
67                 }
68
69                 internal CheckBox (string render_type) : base (HtmlTextWriterTag.Input)
70                 {
71                         this.render_type = render_type;
72                 }
73
74                 [DefaultValue (false)]
75 #if NET_2_0
76                 [Themeable (false)]
77 #endif          
78                 [WebSysDescription ("")]
79                 [WebCategory ("Behavior")]
80                 public virtual bool AutoPostBack 
81                 {
82                         get {
83                                 return (ViewState.GetBool ("AutoPostBack",
84                                                            false));
85                         }
86                         set {
87                                 ViewState["AutoPostBack"] = value;
88                         }
89                 }
90
91 #if NET_2_0
92                 [DefaultValue (false)]
93                 [Themeable (false)]
94                 [WebSysDescription ("")]
95                 [WebCategory ("Behavior")]
96                 public virtual bool CausesValidation 
97                 {
98                         get { return ViewState.GetBool ("CausesValidation", false); }
99                         set { ViewState ["CausesValidation"] = value; }
100                 }
101 #endif          
102                 
103
104                 [DefaultValue (false)]
105 #if NET_2_0
106                 [Bindable (true, BindingDirection.TwoWay)]
107                 [Themeable (false)]
108 #else           
109                 [Bindable (true)]
110 #endif          
111                 [WebSysDescription ("")]
112                 [WebCategory ("Behavior")]
113                 public virtual bool Checked 
114                 {
115                         get {
116                                 return (ViewState.GetBool ("Checked", false));
117                         }
118                         set {
119                                 ViewState["Checked"] = value;
120                         }
121                 }
122
123 #if NET_2_0
124                 [Browsable (false)]
125                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
126                 public AttributeCollection InputAttributes 
127                 {
128                         get {
129                                 if (inputAttributes == null) {
130                                         if (inputAttributesState == null) {
131                                                 inputAttributesState = new StateBag (true);
132                                                 if (IsTrackingViewState)
133                                                         inputAttributesState.TrackViewState();
134                                         }
135                                         inputAttributes = new AttributeCollection (inputAttributesState);
136                                 }
137                                 return inputAttributes;
138                         }
139                 }
140
141                 [Browsable (false)]
142                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
143                 public AttributeCollection LabelAttributes
144                 {
145                         get {
146                                 if (labelAttributes == null) {
147                                         if (labelAttributesState == null) {
148                                                 labelAttributesState = new StateBag (true);
149                                                 if (IsTrackingViewState)
150                                                         labelAttributesState.TrackViewState();
151                                         }
152                                         labelAttributes = new AttributeCollection (labelAttributesState);
153                                 }
154                                 return labelAttributes;
155                         }
156                 }
157 #endif          
158
159                 [DefaultValue ("")]
160                 [Bindable (true)]
161 #if NET_2_0
162                 [Localizable (true)]
163 #endif          
164                 [WebSysDescription ("")]
165                 [WebCategory ("Appearance")]
166                 public virtual string Text 
167                 {
168                         get {
169                                 return (ViewState.GetString ("Text",
170                                                              String.Empty));
171                         }
172                         set {
173                                 ViewState["Text"] = value;
174                         }
175                 }
176
177                 [DefaultValue (TextAlign.Right)]
178 #if ONLY_1_1
179                 [Bindable (true)]
180 #endif          
181                 [WebSysDescription ("")]
182                 [WebCategory ("Appearance")]
183                 public virtual TextAlign TextAlign
184                 {
185                         get { return (TextAlign) ViewState.GetInt ("TextAlign", (int)TextAlign.Right); }
186                         set {
187                                 if (value != TextAlign.Left &&
188                                     value != TextAlign.Right) {
189                                         throw new ArgumentOutOfRangeException ("value");
190                                 }
191                                 
192                                 ViewState["TextAlign"] = value;
193                         }
194                 }
195
196 #if NET_2_0
197                 [Themeable (false)]
198                 [DefaultValue ("")]
199                 [WebSysDescription ("")]
200                 [WebCategoryAttribute ("Behavior")]
201                 public virtual string ValidationGroup
202                 {
203                         get { return ViewState.GetString ("ValidationGroup", String.Empty); }
204                         set { ViewState["ValidationGroup"] = value; }
205                 }
206 #endif          
207
208                 static readonly object EventCheckedChanged = new object ();
209                 [WebSysDescription ("")]
210                 [WebCategory ("Action")]
211                 public event EventHandler CheckedChanged 
212                 {
213                         add {
214                                 Events.AddHandler (EventCheckedChanged, value);
215                         }
216                         remove {
217                                 Events.RemoveHandler (EventCheckedChanged, value);
218                         }
219                 }
220
221                 protected virtual void OnCheckedChanged (EventArgs e)
222                 {
223                         EventHandler handler = (EventHandler)Events[EventCheckedChanged];
224                         
225                         if (handler != null) {
226                                 handler (this, e);
227                         }
228                 }
229
230                 internal virtual string NameAttribute 
231                 {
232                         get {
233                                 return (this.UniqueID);
234                         }
235                 }
236                 
237 #if NET_2_0
238                 protected override void LoadViewState (object savedState)
239                 {
240                         if (savedState == null) {
241                                 base.LoadViewState (null);
242                                 return;
243                         }
244
245                         Triplet saved = (Triplet) savedState;
246                         base.LoadViewState (saved.First);
247
248                         if (saved.Second != null) {
249                                 if (inputAttributesState == null) {
250                                         inputAttributesState = new StateBag(true);
251                                         inputAttributesState.TrackViewState ();
252                                 }
253                                 inputAttributesState.LoadViewState (saved.Second);
254                         }
255
256                         if (saved.Third != null) {
257                                 if (labelAttributesState == null) {
258                                         labelAttributesState = new StateBag(true);
259                                         labelAttributesState.TrackViewState ();
260                                 }
261                                 labelAttributesState.LoadViewState (saved.Third);
262                         }
263                 }
264
265                 protected override object SaveViewState ()
266                 {
267                         object baseView = base.SaveViewState ();
268                         object inputAttrView = null;
269                         object labelAttrView = null;
270
271                         if (inputAttributesState != null)
272                                 inputAttrView = inputAttributesState.SaveViewState ();
273
274                         if (labelAttributesState != null)
275                                 labelAttrView = labelAttributesState.SaveViewState ();
276
277                         if (baseView == null && inputAttrView == null && labelAttrView == null)
278                                 return null;
279
280                         return new Triplet (baseView, inputAttrView, labelAttrView);            
281                 }
282
283                 protected override void TrackViewState ()
284                 {
285                         base.TrackViewState();
286                         if (inputAttributesState != null)
287                                 inputAttributesState.TrackViewState ();
288                         if (labelAttributesState != null)
289                                 labelAttributesState.TrackViewState ();
290                 }
291 #endif          
292
293 #if NET_2_0
294                 protected internal
295 #else           
296                 protected
297 #endif          
298                 override void OnPreRender (EventArgs e)
299                 {
300                         base.OnPreRender (e);
301                         Page page = Page;
302                         bool enabled = Enabled;
303                         
304                         if (page != null && enabled) {
305                                 page.RegisterRequiresPostBack (this);
306                         }
307 #if NET_2_0
308                         if (Page != null && enabled)
309                                 page.RegisterEnabledControl (this);
310 #endif
311                 }
312
313                 static bool IsInputOrCommonAttr (string attname)
314                 {
315                         attname = attname.ToUpper (Helpers.InvariantCulture);
316                         switch (attname) {
317                         case "VALUE":
318                         case "CHECKED":
319                         case "SIZE":
320                         case "MAXLENGTH":
321                         case "SRC":
322                         case "ALT":
323                         case "USEMAP":
324                         case "DISABLED":
325                         case "READONLY":
326                         case "ACCEPT":
327                         case "ACCESSKEY":
328                         case "TABINDEX":
329                         case "ONFOCUS":
330                         case "ONBLUR":
331                         case "ONSELECT":
332                         case "ONCHANGE":
333                         case "ONCLICK":
334                         case "ONDBLCLICK":
335                         case "ONMOUSEDOWN":
336                         case "ONMOUSEUP":
337                         case "ONMOUSEOVER":
338                         case "ONMOUSEMOVE":
339                         case "ONMOUSEOUT":
340                         case "ONKEYPRESS":
341                         case "ONKEYDOWN":
342                         case "ONKEYUP":
343                                 return true;
344                         default:
345                                 return false;
346                         }
347                 }
348
349                 bool AddAttributesForSpan (HtmlTextWriter writer)
350                 {
351                         if (HasAttributes) {
352                                 AttributeCollection attributes = Attributes;
353                                 ICollection k = attributes.Keys;
354                                 string [] keys = new string [k.Count];
355                                 k.CopyTo (keys, 0);
356                                 foreach (string key in keys) {
357                                         if (!IsInputOrCommonAttr (key))
358                                                 continue;
359                                         if (common_attrs == null)
360                                                 common_attrs = new AttributeCollection (new StateBag ());
361                                         common_attrs [key] = Attributes [key];
362                                         attributes.Remove (key);
363                                 }
364                         
365                                 if (attributes.Count > 0) {
366                                         attributes.AddAttributes (writer);
367                                         return true;
368                                 }
369                         }
370                         
371                         return false;
372                 }
373 #if NET_2_0
374                 protected internal
375 #else           
376                 protected
377 #endif          
378                 override void Render (HtmlTextWriter w)
379                 {
380                         Page page = Page;
381                         if (page != null) {
382                                 page.VerifyRenderingInServerForm (this);
383 #if NET_2_0
384                                 page.ClientScript.RegisterForEventValidation (UniqueID);
385 #endif
386                         }
387                         
388                         bool need_span = ControlStyleCreated && !ControlStyle.IsEmpty;
389                         if (need_span) {
390 #if NET_2_0
391                                 AddDisplayStyleAttribute (w);
392 #endif
393                                 ControlStyle.AddAttributesToRender (w, this);
394                         }
395
396                         if (!Enabled) {
397                                 w.AddAttribute (HtmlTextWriterAttribute.Disabled, "disabled", false);
398                                 need_span = true;
399                         }
400
401                         string tt = ToolTip;
402                         if (tt != null && tt.Length > 0){
403                                 w.AddAttribute ("title", tt);
404                                 need_span = true;
405                         }
406
407 #if NET_2_0
408                         if (HasAttributes && AddAttributesForSpan (w))
409                                 need_span = true;
410 #else
411                         if (Attributes.Count > 0 && AddAttributesForSpan (w))
412                                 need_span = true;
413 #endif
414
415                         if (need_span)
416                                 w.RenderBeginTag (HtmlTextWriterTag.Span);
417
418                         TextAlign align = TextAlign;
419                         if (align == TextAlign.Right) {
420                                 RenderInput (w);
421                                 RenderLabel (w);
422                         } else {
423                                 RenderLabel (w);
424                                 RenderInput (w);
425                         }
426
427                         if (need_span)
428                                 w.RenderEndTag ();
429                 }
430
431                 void RenderInput (HtmlTextWriter w) {
432
433                         if (ClientID != null && ClientID.Length > 0)
434                                 w.AddAttribute (HtmlTextWriterAttribute.Id, ClientID);
435                         w.AddAttribute (HtmlTextWriterAttribute.Type, render_type);
436                         string nameAttr = NameAttribute;
437                         if (nameAttr != null && nameAttr.Length > 0)
438                                 w.AddAttribute (HtmlTextWriterAttribute.Name, nameAttr);
439                         InternalAddAttributesToRender (w);
440 #if NET_2_0
441                         AddAttributesToRender (w);
442                         if (inputAttributes != null)
443                                 inputAttributes.AddAttributes (w);
444 #endif
445                         if (Checked)
446                                 w.AddAttribute (HtmlTextWriterAttribute.Checked, "checked", false);
447
448                         if (AutoPostBack) {
449 #if NET_2_0
450                                 string onclick = Page.ClientScript.GetPostBackEventReference (GetPostBackOptions (), true);
451                                 onclick = String.Concat ("setTimeout('", onclick.Replace ("\\", "\\\\").Replace ("'", "\\'"), "', 0)");
452                                 w.AddAttribute (HtmlTextWriterAttribute.Onclick, BuildScriptAttribute ("onclick", onclick));
453 #else
454                                         w.AddAttribute (HtmlTextWriterAttribute.Onclick,
455                                                         BuildScriptAttribute ("onclick", Page.ClientScript.GetPostBackEventReference (this, String.Empty)));
456                                         w.AddAttribute ("language", "javascript", false);
457 #endif
458                         }
459
460                         if (AccessKey.Length > 0)
461                                 w.AddAttribute (HtmlTextWriterAttribute.Accesskey, AccessKey);
462
463                         if (TabIndex != 0)
464                                 w.AddAttribute (HtmlTextWriterAttribute.Tabindex,
465                                                          TabIndex.ToString (NumberFormatInfo.InvariantInfo));
466
467                         if (common_attrs != null)
468                                 common_attrs.AddAttributes (w);
469                         w.RenderBeginTag (HtmlTextWriterTag.Input);
470                         w.RenderEndTag ();
471                 }
472
473                 void RenderLabel (HtmlTextWriter w) {
474                         string text = Text;
475                         if (text.Length > 0) {
476 #if NET_2_0
477                                 if (labelAttributes != null)
478                                         labelAttributes.AddAttributes (w);
479 #endif
480                                 w.AddAttribute (HtmlTextWriterAttribute.For, ClientID);
481                                 w.RenderBeginTag (HtmlTextWriterTag.Label);
482                                 w.Write (text);
483                                 w.RenderEndTag ();
484                         }
485                 }
486
487 #if NET_2_0
488                 protected virtual
489 #endif
490                 bool LoadPostData (string postDataKey, NameValueCollection postCollection)
491                 {
492                         if (!Enabled)
493                                 return false;
494
495                         string postedValue = postCollection[postDataKey];
496                         bool postedBool = ((postedValue != null) &&
497                                            (postedValue.Length > 0));
498                         
499                         if (Checked != postedBool) {
500                                 Checked = postedBool;
501                                 return (true);
502                         }
503
504                         return (false);
505                 }
506
507 #if NET_2_0
508                 protected virtual
509 #endif
510                 void RaisePostDataChangedEvent ()
511                 {
512 #if NET_2_0
513                         ValidateEvent (UniqueID, String.Empty);
514                         if (CausesValidation)
515                                 Page.Validate (ValidationGroup);
516 #endif
517                         OnCheckedChanged (EventArgs.Empty);
518                 }
519
520                 bool IPostBackDataHandler.LoadPostData (string postDataKey, NameValueCollection postCollection)
521                 {
522                         return LoadPostData (postDataKey, postCollection);
523                 }
524                 
525                 void IPostBackDataHandler.RaisePostDataChangedEvent ()
526                 {
527                         RaisePostDataChangedEvent ();
528                 }
529
530 #if NET_2_0
531                 PostBackOptions GetPostBackOptions () {
532                         PostBackOptions options = new PostBackOptions (this);
533                         options.ActionUrl = null;
534                         options.ValidationGroup = null;
535                         options.Argument = String.Empty;
536                         options.RequiresJavaScriptProtocol = false;
537                         options.ClientSubmit = true;
538                         options.PerformValidation = CausesValidation && Page != null && Page.AreValidatorsUplevel (ValidationGroup);
539                         if (options.PerformValidation)
540                                 options.ValidationGroup = ValidationGroup;
541
542                         return options;
543                 }
544
545                 protected override void AddAttributesToRender (HtmlTextWriter writer)
546                 {
547                 }
548 #endif
549
550                 internal virtual void InternalAddAttributesToRender (HtmlTextWriter w)
551                 {
552                         if (!Enabled)
553                                 w.AddAttribute (HtmlTextWriterAttribute.Disabled, "disabled", false);
554                 }
555         }
556 }