Merge pull request #2020 from tomjepp/master
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / WebControl.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //      Peter Bartok    (pbartok@novell.com)
24 //
25 //
26 using System.Collections.Generic;
27 using System.ComponentModel;
28 using System.Drawing;
29 using System.Security.Permissions;
30
31 namespace System.Web.UI.WebControls {
32
33         // CAS
34         [AspNetHostingPermissionAttribute (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
35         [AspNetHostingPermissionAttribute (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
36         // attributes
37         [ParseChildren (true)]
38         [PersistChildrenAttribute (false, false)]
39         [Themeable (true)]
40         public class WebControl : Control, IAttributeAccessor
41         {
42                 const string DEFAULT_DISABLED_CSS_CLASS = "aspNetDisabled";
43                 Style style;
44                 HtmlTextWriterTag tag;
45                 string tag_name;
46                 AttributeCollection attributes;
47                 StateBag attribute_state;
48                 bool enabled;
49                 bool track_enabled_state;
50                 static WebControl ()
51                 {
52                         DisabledCssClass = DEFAULT_DISABLED_CSS_CLASS;
53                 }
54                 public WebControl (HtmlTextWriterTag tag) 
55                 {
56                         this.tag = tag;
57                         this.enabled = true;
58                 }
59
60                 protected WebControl () : this (HtmlTextWriterTag.Span) 
61                 {
62                 }
63
64                 protected WebControl (string tag) 
65                 {
66                         this.tag = HtmlTextWriterTag.Unknown;
67                         this.tag_name = tag;
68                         this.enabled = true;
69                 }
70
71                 [DefaultValue("")]
72                 [WebSysDescription ("")]
73                 [WebCategory ("Behavior")]
74                 public virtual string AccessKey {
75                         get {
76                                 return ViewState.GetString ("AccessKey", string.Empty);
77                         }
78                         set {
79                                 if (value == null || value.Length < 2)
80                                         ViewState ["AccessKey"] = value;
81                                 else
82                                         throw new ArgumentException ("AccessKey can only be null, empty or a single character", "value");
83                         }
84                 }
85
86                 [Browsable(false)]
87                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
88                 [WebSysDescription ("")]
89                 [WebCategory ("Behavior")]
90                 public AttributeCollection Attributes {
91                         get {
92                                 if (attributes == null) {
93                                         attribute_state = new StateBag (true);
94                                         if (IsTrackingViewState)
95                                                 attribute_state.TrackViewState ();
96                                         
97                                         attributes = new AttributeCollection (attribute_state);
98                                 }
99                                 return attributes;
100                         }
101                 }
102
103                 [DefaultValue(typeof (Color), "")]
104                 [TypeConverter(typeof(System.Web.UI.WebControls.WebColorConverter))]
105                 [WebSysDescription ("")]
106                 [WebCategory ("Appearance")]
107                 public virtual Color BackColor {
108                         get {
109                                 if (style == null) 
110                                         return Color.Empty;
111                                 
112                                 return style.BackColor;
113                         }
114                         set {
115                                 ControlStyle.BackColor = value;
116                         }
117                 }
118
119                 [DefaultValue(typeof (Color), "")]
120                 [TypeConverter(typeof(System.Web.UI.WebControls.WebColorConverter))]
121                 [WebSysDescription ("")]
122                 [WebCategory ("Appearance")]
123                 public virtual Color BorderColor {
124                         get {
125                                 if (style == null) 
126                                         return Color.Empty;
127
128                                 return style.BorderColor;
129                         }
130
131                         set {
132                                 ControlStyle.BorderColor = value;
133                         }
134                 }
135
136                 [DefaultValue(BorderStyle.NotSet)]
137                 [WebSysDescription ("")]
138                 [WebCategory ("Appearance")]
139                 public virtual BorderStyle BorderStyle {
140                         get {
141                                 if (style == null) 
142                                         return BorderStyle.NotSet;
143                                 
144                                 return style.BorderStyle;
145                         }
146                         set {
147                                 if (value < BorderStyle.NotSet || value > BorderStyle.Outset)
148                                         throw new ArgumentOutOfRangeException ("value");
149
150                                 ControlStyle.BorderStyle = value;
151                         }
152                 }
153
154                 [DefaultValue(typeof (Unit), "")]
155                 [WebSysDescription ("")]
156                 [WebCategory ("Appearance")]
157                 public virtual Unit BorderWidth {
158                         get {
159                                 if (style == null) 
160                                         return Unit.Empty;
161
162                                 return style.BorderWidth;
163                         }
164                         set { ControlStyle.BorderWidth = value; }
165                 }
166
167                 [Browsable(false)]
168                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
169                 [WebSysDescription ("")]
170                 [WebCategory ("Appearance")]
171                 public Style ControlStyle {
172                         get {
173                                 if (style == null) {
174                                         style = this.CreateControlStyle ();
175
176                                         if (IsTrackingViewState)
177                                                 style.TrackViewState ();
178                                 }
179
180                                 return style;
181                         }
182                 }
183
184                 [Browsable(false)]
185                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
186                 [EditorBrowsable (EditorBrowsableState.Never)]
187                 public bool ControlStyleCreated {
188                         get {
189                                 return style != null;
190                         }
191                 }
192
193                 [CssClassProperty]
194                 [DefaultValue("")]
195                 [WebSysDescription ("")]
196                 [WebCategory ("Appearance")]
197                 public virtual string CssClass {
198                         get {
199                                 if (style == null) 
200                                         return string.Empty;
201                                 
202                                 return style.CssClass;
203                         }
204                         set {
205                                 ControlStyle.CssClass = value;
206                         }
207                 }
208
209                 [Bindable(true)]
210                 [DefaultValue(true)]
211                 [Themeable (false)]
212                 public virtual bool Enabled {
213                         get {
214                                 return enabled;
215                         }
216
217                         set {
218                                 if (enabled != value) {
219                                         if (IsTrackingViewState)
220                                                 track_enabled_state = true;
221                                         enabled = value;
222                                 }
223                         }
224                 }
225
226                 [Browsable (true)]
227                 public virtual new bool EnableTheming
228                 {
229                         get { return base.EnableTheming; }
230                         set { base.EnableTheming = value; }
231                 }
232
233                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
234                 [NotifyParentProperty(true)]
235                 [WebSysDescription ("")]
236                 [WebCategory ("Appearance")]
237                 public virtual FontInfo Font {
238                         get {
239                                 // Oddly enough, it looks like we have to let it create the style
240                                 // since we can't create a FontInfo without a style owner
241                                 return ControlStyle.Font;
242                         }
243                 }
244
245                 [DefaultValue(typeof (Color), "")]
246                 [TypeConverter(typeof(System.Web.UI.WebControls.WebColorConverter))]
247                 [WebSysDescription ("")]
248                 [WebCategory ("Appearance")]
249                 public virtual Color ForeColor {
250                         get {
251                                 if (style == null) 
252                                         return Color.Empty;
253                                 
254                                 return style.ForeColor;
255                         }
256                         set {
257                                 ControlStyle.ForeColor = value;
258                         }
259                 }
260
261                 [Browsable (false)]
262                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
263                 public
264                 bool HasAttributes 
265                 {
266                         get {
267                                 return (attributes != null && attributes.Count > 0);
268                         }
269                 }
270                 
271                 [DefaultValue(typeof (Unit), "")]
272                 [WebSysDescription ("")]
273                 [WebCategory ("Layout")]
274                 public virtual Unit Height {
275                         get {
276                                 if (style == null) 
277                                         return Unit.Empty;
278                                 
279                                 return style.Height;
280                         }
281                         set {
282                                 ControlStyle.Height = value;
283                         }
284                 }
285
286                 [Browsable (true)]
287                 public virtual new string SkinID
288                 {
289                         get { return base.SkinID; }
290                         set { base.SkinID = value; }
291                 }
292                 
293                 [Browsable(false)]
294                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
295                 [WebSysDescription ("")]
296                 [WebCategory ("Style")]
297                 public CssStyleCollection Style {
298                         get {
299                                 return Attributes.CssStyle;
300                         }
301                 }
302
303                 [DefaultValue((short)0)]
304                 [WebSysDescription ("")]
305                 [WebCategory ("Behavior")]
306                 public virtual short TabIndex {
307                         get {
308                                 return ViewState.GetShort ("TabIndex", 0);
309                         }
310                         set {
311                                 ViewState ["TabIndex"] = value;
312                         }
313                 }
314
315                 [DefaultValue("")]
316                 [Localizable (true)]
317                 [WebSysDescription ("")]
318                 [WebCategory ("Behavior")]
319                 public virtual string ToolTip {
320                         get {
321                                 return ViewState.GetString ("ToolTip", string.Empty);
322                         }
323                         set {
324                                 ViewState ["ToolTip"] = value;
325                         }
326                 }
327
328                 [DefaultValue(typeof (Unit), "")]
329                 [WebSysDescription ("")]
330                 [WebCategory ("Layout")]
331                 public virtual Unit Width {
332                         get {
333                                 if (style == null) 
334                                         return Unit.Empty;
335                                 
336                                 return style.Width;
337                         }
338                         set {
339                                 ControlStyle.Width = value;
340                         }
341                 }
342
343                 [Browsable(false)]
344                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
345                 protected virtual HtmlTextWriterTag TagKey {
346                         get {
347                                 return tag;
348                         }
349                 }
350
351                 [Browsable(false)]
352                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
353                 protected virtual string TagName {
354                         get {
355                                 // do this here to avoid potentially costly lookups on every control
356                                 if (tag_name == null)
357                                         tag_name = HtmlTextWriter.StaticGetTagName (TagKey);
358                                 
359                                 return tag_name;
360                         }
361                 }
362
363                 protected
364                 internal bool IsEnabled 
365                 {
366                         get {
367                                 WebControl wc = this;
368                                 while (wc != null) {
369                                         if (!wc.Enabled)
370                                                 return false;
371                                         wc = wc.Parent as WebControl;
372                                 }
373                                 return true;
374                         }
375                 }
376                 public static string DisabledCssClass {
377                         get;
378                         set;
379                 }
380                 
381                 [Browsable (false)]
382                 public virtual bool SupportsDisabledAttribute {
383                         get { return true; }
384                 }
385                 public void ApplyStyle (Style s) 
386                 {
387                         if (s != null && !s.IsEmpty)
388                                 ControlStyle.CopyFrom(s);
389                 }
390
391                 public void CopyBaseAttributes (WebControl controlSrc) 
392                 {
393                         object o;
394
395                         if (controlSrc == null) 
396                                 return;
397
398                         Enabled = controlSrc.Enabled;
399
400                         o = controlSrc.ViewState ["AccessKey"];
401                         if (o != null)
402                                 ViewState ["AccessKey"] = o;
403
404                         o = controlSrc.ViewState ["TabIndex"];
405                         if (o != null)
406                                 ViewState ["TabIndex"] = o;
407
408                         o = controlSrc.ViewState ["ToolTip"];
409                         if (o != null)
410                                 ViewState ["ToolTip"] = o;
411
412                         if (controlSrc.attributes != null) {
413                                 AttributeCollection attributes = Attributes;
414                                 
415                                 foreach (string s in controlSrc.attributes.Keys)
416                                         attributes [s] = controlSrc.attributes [s];
417                         }
418                 }
419
420                 public void MergeStyle (Style s) 
421                 {
422                         if (s != null && !s.IsEmpty)
423                                 ControlStyle.MergeWith(s);
424                 }
425
426                 public virtual void RenderBeginTag (HtmlTextWriter writer)
427                 {
428                         AddAttributesToRender (writer);
429                         
430                         if (TagKey == HtmlTextWriterTag.Unknown)
431                                 writer.RenderBeginTag (TagName);
432                         else
433                                 writer.RenderBeginTag (TagKey);
434                         
435                 }
436
437                 public virtual void RenderEndTag (HtmlTextWriter writer) 
438                 {
439                         writer.RenderEndTag ();
440                 }
441
442                 static char[] _script_trim_chars = {';'};
443                 internal string BuildScriptAttribute (string name, string tail)
444                 {
445                         AttributeCollection attrs = Attributes;
446                         string attr = attrs [name];
447                         
448                         if (attr == null || attr.Length == 0)
449                                 return tail;
450                         if (attr [attr.Length - 1] == ';')
451                                 attr = attr.TrimEnd (_script_trim_chars);
452                         
453                         attr = String.Concat (attr, ";", tail);
454                         attrs.Remove (name);
455                         
456                         return attr;
457                 }
458                 
459                 internal void AddDisplayStyleAttribute (HtmlTextWriter writer)
460                 {
461                         if (!ControlStyleCreated)
462                                 return;
463
464                         if (!ControlStyle.BorderWidth.IsEmpty ||
465                             (ControlStyle.BorderStyle != BorderStyle.None && ControlStyle.BorderStyle != BorderStyle.NotSet) ||
466                             !ControlStyle.Height.IsEmpty ||
467                             !ControlStyle.Width.IsEmpty)
468                                 writer.AddStyleAttribute (HtmlTextWriterStyle.Display, "inline-block");
469                 }
470                 void RenderDisabled (HtmlTextWriter writer)
471                 {
472                         if (!IsEnabled) {
473                                 if (!SupportsDisabledAttribute)
474                                         ControlStyle.PrependCssClass (DisabledCssClass);
475                                 else
476                                         writer.AddAttribute (HtmlTextWriterAttribute.Disabled, "disabled", false);
477                         }
478
479                 }
480                 
481                 protected virtual void AddAttributesToRender (HtmlTextWriter writer) 
482                 {
483                         RenderDisabled (writer);
484                         if (ID != null)
485                                 writer.AddAttribute(HtmlTextWriterAttribute.Id, ClientID);
486                         if (AccessKey != string.Empty)
487                                 writer.AddAttribute (HtmlTextWriterAttribute.Accesskey, AccessKey);
488                         
489                         if (ToolTip != string.Empty)
490                                 writer.AddAttribute (HtmlTextWriterAttribute.Title, ToolTip);
491
492                         if (TabIndex != 0)
493                                 writer.AddAttribute (HtmlTextWriterAttribute.Tabindex, TabIndex.ToString ());
494
495                         if (style != null && !style.IsEmpty) {
496                                 //unbelievable, but see WebControlTest.RenderBeginTag_BorderWidth_xxx
497                                 if (TagKey == HtmlTextWriterTag.Span)
498                                         AddDisplayStyleAttribute (writer);
499                                 style.AddAttributesToRender(writer, this);
500                         }
501
502                         if (attributes != null)
503                                 foreach(string s in attributes.Keys)
504                                         writer.AddAttribute (s, attributes [s]);
505                 }
506
507                 protected virtual Style CreateControlStyle() 
508                 {
509                         return new Style (ViewState);
510                 }
511
512                 protected override void LoadViewState (object savedState) 
513                 {
514                         if (savedState == null || !(savedState is Pair)) {
515                                 base.LoadViewState (null);
516                                 return;
517                         }
518
519                         Pair pair = (Pair) savedState;
520                         
521                         base.LoadViewState (pair.First);
522                         if (ViewState [System.Web.UI.WebControls.Style.BitStateKey] != null)
523                                 ControlStyle.LoadBitState ();
524
525                         if (pair.Second != null) {
526                                 if (attribute_state == null) {
527                                         attribute_state = new StateBag ();
528                                         if (IsTrackingViewState) 
529                                                 attribute_state.TrackViewState ();
530                                 }
531
532                                 attribute_state.LoadViewState (pair.Second);
533                                 attributes = new AttributeCollection(attribute_state);
534                         }
535
536                         enabled = ViewState.GetBool ("Enabled", enabled);
537                 }
538                 internal virtual string InlinePropertiesSet ()
539                 {
540                         var properties = new List <string> ();
541                         
542                         if (BackColor != Color.Empty)
543                                 properties.Add ("BackColor");
544
545                         if (BorderColor != Color.Empty)
546                                 properties.Add ("BorderColor");
547
548                         if (BorderStyle != BorderStyle.NotSet)
549                                 properties.Add ("BorderStyle");
550
551                         if (BorderWidth != Unit.Empty)
552                                 properties.Add ("BorderWidth");
553
554                         if (CssClass != String.Empty)
555                                 properties.Add ("CssClass");
556
557                         if (ForeColor != Color.Empty)
558                                 properties.Add ("ForeColor");
559
560                         if (Height != Unit.Empty)
561                                 properties.Add ("Height");
562
563                         if (Width != Unit.Empty)
564                                 properties.Add ("Width");
565
566                         if (properties.Count == 0)
567                                 return null;
568
569                         return String.Join (", ", properties);
570                 }
571
572                 internal void VerifyInlinePropertiesNotSet ()
573                 {
574                         var renderOuterTableControl = this as IRenderOuterTable;
575                         if (renderOuterTableControl == null || renderOuterTableControl.RenderOuterTable)
576                                 return;
577
578                         string properties = InlinePropertiesSet ();
579                         if (!String.IsNullOrEmpty (properties)) {
580                                 bool many = properties.IndexOf (',') > -1;
581                                 throw new InvalidOperationException (
582                                         String.Format ("The style propert{0} '{1}' cannot be used while RenderOuterTable is disabled on the {2} control with ID '{3}'",
583                                                        many ? "ies" : "y",
584                                                        properties,
585                                                        GetType ().Name,
586                                                        ID)
587                                 );
588                         }
589                 }
590                 protected internal
591                 override void Render (HtmlTextWriter writer)
592                 {
593                         if (Adapter != null) {
594                                 Adapter.Render(writer);
595                                 return;
596                         }
597                         RenderBeginTag (writer);
598                         RenderContents (writer);
599                         RenderEndTag (writer);
600                 }
601
602                 protected internal
603                 virtual void RenderContents (HtmlTextWriter writer)
604                 {
605                         base.Render (writer);
606                 }
607
608                 protected override object SaveViewState () 
609                 {
610                         if (track_enabled_state)
611                                 ViewState ["Enabled"] = enabled;
612
613                         object view_state;
614                         object attr_view_state = null;
615
616                         if (style != null)
617                                 style.SaveBitState ();
618                         view_state = base.SaveViewState ();
619
620                         if (attribute_state != null)
621                                 attr_view_state = attribute_state.SaveViewState ();
622                 
623                         if (view_state == null && attr_view_state == null)
624                                 return null;
625
626                         return new Pair (view_state, attr_view_state);
627                 }
628
629                 protected override void TrackViewState() 
630                 {
631                         if (style != null)
632                                 style.TrackViewState ();
633
634                         if (attribute_state != null) {
635                                 attribute_state.TrackViewState ();
636                                 attribute_state.SetDirty (true);
637                         }
638
639                         base.TrackViewState ();
640                 }
641
642                 string IAttributeAccessor.GetAttribute (string key) 
643                 {
644                         if (attributes != null)
645                                 return attributes [key];
646
647                         return null;
648                 }
649
650                 void IAttributeAccessor.SetAttribute (string key, string value) 
651                 {
652                         Attributes [key] = value;
653                 }
654         }
655 }