**** Merged r40732-r40872 from MCS ****
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / CheckBox.cs
1 //
2 // System.Web.UI.WebControls.CheckBox.cs
3 //
4 // Authors:
5 //   Gaurav Vaish (gvaish@iitk.ac.in)
6 //   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
7 //
8 // (C) Gaurav Vaish (2002)
9 // (C) 2003 Andreas Nahr
10 // Thanks to Leen Toelen (toelen@hotmail.com)'s classes that helped me
11 // to write the contents of the function LoadPostData(...)
12 //
13
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using System;
36 using System.Collections;
37 using System.Collections.Specialized;
38 using System.Globalization;
39 using System.Web;
40 using System.Web.UI;
41 using System.ComponentModel;
42 using System.ComponentModel.Design;
43
44 namespace System.Web.UI.WebControls
45 {
46 #if NET_2_0
47         [ControlValuePropertyAttribute ("Checked")]
48 #endif
49         [DefaultEvent("CheckedChanged")]
50         [DefaultProperty("Text")]
51         [DataBindingHandler("System.Web.UI.Design.TextDataBindingHandler, " + Consts.AssemblySystem_Design)]
52         [Designer ("System.Web.UI.Design.WebControls.CheckBoxDesigner, " + Consts.AssemblySystem_Design, typeof (IDesigner))]
53         public class CheckBox : WebControl, IPostBackDataHandler
54 #if NET_2_0
55                 , ICheckBoxControl
56 #endif
57         {
58                 private static readonly object CheckedChangedEvent = new object();
59                 AttributeCollection commonAttrs;
60                 
61 #if NET_2_0
62                 AttributeCollection inputAttributes;
63                 StateBag inputAttributesState;
64                 AttributeCollection labelAttributes;
65                 StateBag labelAttributesState;
66 #endif
67                 
68                 public CheckBox(): base(HtmlTextWriterTag.Input)
69                 {
70                 }
71
72 #if NET_2_0
73             [ThemeableAttribute (false)]
74 #endif
75                 [DefaultValue (false), WebCategory ("Behavior")]
76                 [WebSysDescription ("The control automatically posts back after changing the text.")]
77                 public virtual bool AutoPostBack
78                 {
79                         get {
80                                  object o = ViewState ["AutoPostBack"];
81                                  return (o == null) ? false : (bool) o;
82                         }
83
84                         set { ViewState ["AutoPostBack"] = value; }
85                 }
86
87
88 #if NET_2_0
89             [ThemeableAttribute (false)]
90 #endif
91                 [DefaultValue (false), Bindable (true)]
92                 [WebSysDescription ("Determines if the control is checked.")]
93                 public virtual bool Checked
94                 {
95                         get {
96                                 object o = ViewState ["Checked"];
97                                 return (o == null) ? false : (bool) o;
98                         }
99
100                         set { ViewState ["Checked"] = value; }
101                 }
102
103 #if NET_2_0
104             [Localizable (true)]
105 #endif
106                 [DefaultValue (""), Bindable (true), WebCategory ("Appearance")]
107                 [WebSysDescription ("The text that this control displays.")]
108                 public virtual string Text
109                 {
110                         get {
111                                 object o = ViewState ["Text"];
112                                 return (o == null) ? String.Empty : (string) o;
113                         }
114
115                         set { ViewState ["Text"] = value; }
116                 }
117                 
118                 private bool SaveCheckedViewState
119                 {
120                         get {
121                                 if (Events [CheckedChangedEvent] != null || !Enabled)
122                                         return true;
123
124                                 Type type = GetType ();
125                                 return (type != typeof (CheckBox) && type != typeof (RadioButton));
126                         }
127                 }
128
129 #if !NET_2_0
130                 [Bindable (true)]
131 #endif
132                 [DefaultValue (typeof (TextAlign), "Right"), WebCategory ("Appearance")]
133                 [WebSysDescription ("The alignment of the text.")]
134                 public virtual TextAlign TextAlign
135                 {
136                         get {
137                                 object o = ViewState ["TextAlign"];
138                                 return (o == null) ? TextAlign.Right : (TextAlign) o;
139                         }
140
141                         set {
142                                 if (!System.Enum.IsDefined (typeof (TextAlign), value))
143                                         throw new ArgumentException ();
144                                 ViewState ["TextAlign"] = value;
145                         }
146                 }
147
148 #if NET_2_0
149         [ThemeableAttribute (false)]
150                 [DefaultValue (false), WebCategory ("Behavior")]
151                 public bool CausesValidation
152                 {
153                         get
154                         {
155                                 Object cv = ViewState["CausesValidation"];
156                                 if(cv!=null)
157                                         return (Boolean)cv;
158                                 return false;
159                         }
160                         set
161                         {
162                                 ViewState["CausesValidation"] = value;
163                         }
164                 }
165                 
166                 [Browsable (false), DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
167                 public AttributeCollection InputAttributes
168                 {
169                         get {
170                                 if (inputAttributes == null) {
171                                         if (inputAttributesState == null) {
172                                                 inputAttributesState = new StateBag (true);
173                                                 if (IsTrackingViewState)
174                                                         inputAttributesState.TrackViewState();
175                                         }
176                                         inputAttributes = new AttributeCollection (inputAttributesState);
177                                 }
178                                 return inputAttributes;
179                         }
180                 }
181                 
182                 [Browsable (false), DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
183                 public AttributeCollection LabelAttributes
184                 {
185                         get {
186                                 if (labelAttributes == null) {
187                                         if (labelAttributesState == null) {
188                                                 labelAttributesState = new StateBag (true);
189                                                 if (IsTrackingViewState)
190                                                         labelAttributesState.TrackViewState();
191                                         }
192                                         labelAttributes = new AttributeCollection (labelAttributesState);
193                                 }
194                                 return labelAttributes;
195                         }
196                 }
197
198                 [DefaultValueAttribute ("")]
199                 [ThemeableAttribute (false)]
200                 [WebCategoryAttribute ("Behavior")]
201                 public string ValidationGroup {
202                         get {
203                                 string text = (string)ViewState["ValidationGroup"];
204                                 if (text!=null) return text;
205                                 return String.Empty;
206                         }
207                         set {
208                                 ViewState["ValidationGroup"] = value;
209                         }
210                 }
211                 
212 #endif
213
214                 [WebCategory ("Action")]
215                 [WebSysDescription ("Raised when the control is checked or unchecked.")]
216                 public event EventHandler CheckedChanged
217                 {
218                         add { Events.AddHandler (CheckedChangedEvent, value); }
219                         remove { Events.RemoveHandler (CheckedChangedEvent, value); }
220                 }
221                 
222                 protected virtual void OnCheckedChanged(EventArgs e)
223                 {
224                         if(Events != null){
225                                 EventHandler eh = (EventHandler) (Events [CheckedChangedEvent]);
226                                 if(eh != null)
227                                         eh (this, e);
228                         }
229                 }
230                 
231 #if NET_2_0
232                 protected override void TrackViewState ()
233                 {
234                         base.TrackViewState();
235                         if (inputAttributesState != null)
236                                 inputAttributesState.TrackViewState ();
237                         if (labelAttributesState != null)
238                                 labelAttributesState.TrackViewState ();
239                 }
240
241                 protected override object SaveViewState ()
242                 {
243                         object baseView = base.SaveViewState ();
244                         object inputAttrView = null;
245                         object labelAttrView = null;
246                         
247                         if (inputAttributesState != null)
248                                 inputAttrView = inputAttributesState.SaveViewState ();
249                         
250                         if (labelAttributesState != null)
251                                 labelAttrView = labelAttributesState.SaveViewState ();
252                         
253                         if (baseView == null && inputAttrView == null && labelAttrView == null)
254                                 return null;
255
256                         return new Triplet (baseView, inputAttrView, labelAttrView);
257                 }
258
259                 protected override void LoadViewState (object savedState)
260                 {
261                         if (savedState == null)
262                                 return;
263
264                         Triplet saved = (Triplet) savedState;
265                         base.LoadViewState (saved.First);
266                         
267                         if (saved.Second != null) {
268                                 if (inputAttributesState == null) {
269                                         inputAttributesState = new StateBag(true);
270                                         inputAttributesState.TrackViewState ();
271                                 }
272                                 inputAttributesState.LoadViewState (saved.Second);
273                         }
274                         
275                         if (saved.Third != null) {
276                                 if (labelAttributesState == null) {
277                                         labelAttributesState = new StateBag(true);
278                                         labelAttributesState.TrackViewState ();
279                                 }
280                                 labelAttributesState.LoadViewState (saved.Third);
281                         }
282                 }
283 #endif
284
285                 protected override void OnPreRender(EventArgs e)
286                 {
287                         if (Page != null && Enabled) {
288                                 Page.RegisterRequiresPostBack (this);
289                                 if (AutoPostBack)
290                                         Page.RequiresPostBackScript ();
291                         }
292
293                         if (!SaveCheckedViewState)
294                                 ViewState.SetItemDirty ("Checked", false);
295                 }
296
297                 static bool IsInputOrCommonAttr (string attname)
298                 {
299                         switch (attname) {
300                         case "VALUE":
301                         case "CHECKED":
302                         case "SIZE":
303                         case "MAXLENGTH":
304                         case "SRC":
305                         case "ALT":
306                         case "USEMAP":
307                         case "DISABLED":
308                         case "READONLY":
309                         case "ACCEPT":
310                         case "ACCESSKEY":
311                         case "TABINDEX":
312                         case "ONFOCUS":
313                         case "ONBLUR":
314                         case "ONSELECT":
315                         case "ONCHANGE":
316                         case "ONCLICK":
317                         case "ONDBLCLICK":
318                         case "ONMOUSEDOWN":
319                         case "ONMOUSEUP":
320                         case "ONMOUSEOVER":
321                         case "ONMOUSEMOVE":
322                         case "ONMOUSEOUT":
323                         case "ONKEYPRESS":
324                         case "ONKEYDOWN":
325                         case "ONKEYUP":
326                                 return true;
327                         default:
328                                 return false;
329                         }
330                 }
331
332                 void AddAttributesForSpan (HtmlTextWriter writer)
333                 {
334                         ICollection k = Attributes.Keys;
335                         string [] keys = new string [k.Count];
336                         k.CopyTo (keys, 0);
337                         foreach (string key in keys) {
338                                 if (!IsInputOrCommonAttr (key.ToUpper ()))
339                                         continue;
340
341                                 if (commonAttrs == null)
342                                         commonAttrs = new AttributeCollection (new StateBag ());
343
344                                 commonAttrs [key] = Attributes [key];
345                                 Attributes.Remove (key);
346                         }
347
348                         Attributes.AddAttributes (writer);
349                 }
350
351 #if NET_2_0
352                 protected override void AddAttributesToRender (HtmlTextWriter writer)
353                 {
354                         base.AddAttributesToRender (writer);
355                 }
356 #endif
357                 
358                 protected override void Render (HtmlTextWriter writer)
359                 {
360                         bool hasBeginRendering = false;
361                         if(ControlStyleCreated && !ControlStyle.IsEmpty){
362                                 hasBeginRendering = true;
363                                 ControlStyle.AddAttributesToRender (writer, this);
364                         }
365                         
366                         if (!Enabled)\r
367                         {
368                                 hasBeginRendering = true;\r
369                                 writer.AddAttribute(HtmlTextWriterAttribute.Disabled, "disabled");                              \r
370                         }
371
372                         if (ToolTip.Length > 0){
373                                 hasBeginRendering = true;
374                                 writer.AddAttribute (HtmlTextWriterAttribute.Title, ToolTip);
375                         }
376
377                         if (Attributes.Count > 0){
378                                 hasBeginRendering = true;
379                                 AddAttributesForSpan (writer);
380                         }
381
382                         if (hasBeginRendering)
383                                 writer.RenderBeginTag (HtmlTextWriterTag.Span);
384
385                         if (Text.Length > 0){
386                                 TextAlign ta = TextAlign;
387                                 if(ta == TextAlign.Right) {
388                                         if (commonAttrs != null)
389                                                 commonAttrs.AddAttributes (writer);
390                                         RenderInputTag (writer, ClientID);
391                                 }
392 #if NET_2_0
393                                 if (labelAttributes != null)
394                                         labelAttributes.AddAttributes (writer);
395 #endif
396                                 writer.AddAttribute (HtmlTextWriterAttribute.For, ClientID);
397                                 writer.RenderBeginTag (HtmlTextWriterTag.Label);
398                                 writer.Write (Text);
399                                 writer.RenderEndTag ();
400                                 if(ta == TextAlign.Left) {
401                                         if (commonAttrs != null)
402                                                 commonAttrs.AddAttributes (writer);
403                                         RenderInputTag (writer, ClientID);
404                                 }
405                         } else {
406                                 if (commonAttrs != null)
407                                         commonAttrs.AddAttributes (writer);
408                                 RenderInputTag (writer, ClientID);
409                         }
410
411                         if (hasBeginRendering)
412                                 writer.RenderEndTag ();
413                 }
414                 
415                 internal virtual void RenderInputTag (HtmlTextWriter writer, string clientId)
416                 {
417 #if NET_2_0
418                         if (inputAttributes != null)
419                                 inputAttributes.AddAttributes (writer);
420 #endif
421                         if (!Enabled)
422                                 writer.AddAttribute (HtmlTextWriterAttribute.Disabled, "disabled");
423
424                         writer.AddAttribute (HtmlTextWriterAttribute.Id, clientId);
425                         writer.AddAttribute( HtmlTextWriterAttribute.Type, "checkbox");
426                         writer.AddAttribute (HtmlTextWriterAttribute.Name, UniqueID);
427                         if (Checked)
428                                 writer.AddAttribute (HtmlTextWriterAttribute.Checked, "checked");
429
430                         if (AutoPostBack){
431                                 writer.AddAttribute (HtmlTextWriterAttribute.Onclick,
432                                                      Page.ClientScript.GetPostBackClientEvent (this, String.Empty));
433                                 writer.AddAttribute ("language", "javascript");
434                         }
435
436                         if (AccessKey.Length > 0)
437                                 writer.AddAttribute (HtmlTextWriterAttribute.Accesskey, AccessKey);
438
439                         if (TabIndex != 0)
440                                 writer.AddAttribute (HtmlTextWriterAttribute.Tabindex,
441                                                      TabIndex.ToString (NumberFormatInfo.InvariantInfo));
442
443                         writer.RenderBeginTag (HtmlTextWriterTag.Input);
444                         writer.RenderEndTag ();
445                 }
446                 
447 #if NET_2_0
448                 bool IPostBackDataHandler.LoadPostData (string postDataKey, NameValueCollection postCollection)
449                 {
450                         return LoadPostData (postDataKey, postCollection);
451                 }
452                 
453                 protected virtual bool LoadPostData (string postDataKey, NameValueCollection postCollection)
454 #else
455                 bool IPostBackDataHandler.LoadPostData (string postDataKey, NameValueCollection postCollection)
456 #endif
457                 {
458                         string postedVal = postCollection [postDataKey];                        \r
459                         bool haveData = ((postedVal != null)&& (postedVal.Length > 0));\r
460                         bool diff  = (haveData != Checked);
461                         Checked = haveData;
462                         return diff ;
463                 }
464                 
465 #if NET_2_0
466                 void IPostBackDataHandler.RaisePostDataChangedEvent()
467                 {
468                         RaisePostDataChangedEvent ();
469                 }
470                 
471                 protected virtual void RaisePostDataChangedEvent()
472                 {
473                         if (CausesValidation)
474                                 Page.Validate (ValidationGroup);
475
476                         OnCheckedChanged (EventArgs.Empty);
477                 }
478 #else
479                 void IPostBackDataHandler.RaisePostDataChangedEvent()
480                 {
481                         OnCheckedChanged (EventArgs.Empty);
482                 }
483 #endif
484         }
485 }