Merge pull request #1458 from BrzVlad/feature-fat-cas
[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 #if ONLY_1_1
72                 [Bindable(true)]
73 #endif          
74                 [DefaultValue("")]
75                 [WebSysDescription ("")]
76                 [WebCategory ("Behavior")]
77                 public virtual string AccessKey {
78                         get {
79                                 return ViewState.GetString ("AccessKey", string.Empty);
80                         }
81                         set {
82                                 if (value == null || value.Length < 2)
83                                         ViewState ["AccessKey"] = value;
84                                 else
85                                         throw new ArgumentException ("AccessKey can only be null, empty or a single character", "value");
86                         }
87                 }
88
89                 [Browsable(false)]
90                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
91                 [WebSysDescription ("")]
92                 [WebCategory ("Behavior")]
93                 public AttributeCollection Attributes {
94                         get {
95                                 if (attributes == null) {
96                                         attribute_state = new StateBag (true);
97                                         if (IsTrackingViewState)
98                                                 attribute_state.TrackViewState ();
99                                         
100                                         attributes = new AttributeCollection (attribute_state);
101                                 }
102                                 return attributes;
103                         }
104                 }
105
106 #if ONLY_1_1
107                 [Bindable(true)]
108 #endif          
109                 [DefaultValue(typeof (Color), "")]
110                 [TypeConverter(typeof(System.Web.UI.WebControls.WebColorConverter))]
111                 [WebSysDescription ("")]
112                 [WebCategory ("Appearance")]
113                 public virtual Color BackColor {
114                         get {
115                                 if (style == null) 
116                                         return Color.Empty;
117                                 
118                                 return style.BackColor;
119                         }
120                         set {
121                                 ControlStyle.BackColor = value;
122                         }
123                 }
124
125 #if ONLY_1_1
126                 [Bindable(true)]
127 #endif          
128                 [DefaultValue(typeof (Color), "")]
129                 [TypeConverter(typeof(System.Web.UI.WebControls.WebColorConverter))]
130                 [WebSysDescription ("")]
131                 [WebCategory ("Appearance")]
132                 public virtual Color BorderColor {
133                         get {
134                                 if (style == null) 
135                                         return Color.Empty;
136
137                                 return style.BorderColor;
138                         }
139
140                         set {
141                                 ControlStyle.BorderColor = value;
142                         }
143                 }
144
145 #if ONLY_1_1
146                 [Bindable(true)]
147 #endif          
148                 [DefaultValue(BorderStyle.NotSet)]
149                 [WebSysDescription ("")]
150                 [WebCategory ("Appearance")]
151                 public virtual BorderStyle BorderStyle {
152                         get {
153                                 if (style == null) 
154                                         return BorderStyle.NotSet;
155                                 
156                                 return style.BorderStyle;
157                         }
158                         set {
159                                 if (value < BorderStyle.NotSet || value > BorderStyle.Outset)
160                                         throw new ArgumentOutOfRangeException ("value");
161
162                                 ControlStyle.BorderStyle = value;
163                         }
164                 }
165
166 #if ONLY_1_1
167                 [Bindable(true)]
168 #endif          
169                 [DefaultValue(typeof (Unit), "")]
170                 [WebSysDescription ("")]
171                 [WebCategory ("Appearance")]
172                 public virtual Unit BorderWidth {
173                         get {
174                                 if (style == null) 
175                                         return Unit.Empty;
176
177                                 return style.BorderWidth;
178                         }
179                         set { ControlStyle.BorderWidth = value; }
180                 }
181
182                 [Browsable(false)]
183                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
184                 [WebSysDescription ("")]
185                 [WebCategory ("Appearance")]
186                 public Style ControlStyle {
187                         get {
188                                 if (style == null) {
189                                         style = this.CreateControlStyle ();
190
191                                         if (IsTrackingViewState)
192                                                 style.TrackViewState ();
193                                 }
194
195                                 return style;
196                         }
197                 }
198
199                 [Browsable(false)]
200                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
201                 [EditorBrowsable (EditorBrowsableState.Never)]
202                 public bool ControlStyleCreated {
203                         get {
204                                 return style != null;
205                         }
206                 }
207
208                 [CssClassProperty]
209                 [DefaultValue("")]
210                 [WebSysDescription ("")]
211                 [WebCategory ("Appearance")]
212                 public virtual string CssClass {
213                         get {
214                                 if (style == null) 
215                                         return string.Empty;
216                                 
217                                 return style.CssClass;
218                         }
219                         set {
220                                 ControlStyle.CssClass = value;
221                         }
222                 }
223
224                 [Bindable(true)]
225                 [DefaultValue(true)]
226                 [Themeable (false)]
227                 public virtual bool Enabled {
228                         get {
229                                 return enabled;
230                         }
231
232                         set {
233                                 if (enabled != value) {
234                                         if (IsTrackingViewState)
235                                                 track_enabled_state = true;
236                                         enabled = value;
237                                 }
238                         }
239                 }
240
241                 [Browsable (true)]
242                 public virtual new bool EnableTheming
243                 {
244                         get { return base.EnableTheming; }
245                         set { base.EnableTheming = value; }
246                 }
247
248 #if ONLY_1_1
249                 [DefaultValue(null)]
250 #endif          
251                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
252                 [NotifyParentProperty(true)]
253                 [WebSysDescription ("")]
254                 [WebCategory ("Appearance")]
255                 public virtual FontInfo Font {
256                         get {
257                                 // Oddly enough, it looks like we have to let it create the style
258                                 // since we can't create a FontInfo without a style owner
259                                 return ControlStyle.Font;
260                         }
261                 }
262
263 #if ONLY_1_1
264                 [Bindable(true)]
265 #endif          
266                 [DefaultValue(typeof (Color), "")]
267                 [TypeConverter(typeof(System.Web.UI.WebControls.WebColorConverter))]
268                 [WebSysDescription ("")]
269                 [WebCategory ("Appearance")]
270                 public virtual Color ForeColor {
271                         get {
272                                 if (style == null) 
273                                         return Color.Empty;
274                                 
275                                 return style.ForeColor;
276                         }
277                         set {
278                                 ControlStyle.ForeColor = value;
279                         }
280                 }
281
282                 [Browsable (false)]
283                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
284                 public
285                 bool HasAttributes 
286                 {
287                         get {
288                                 return (attributes != null && attributes.Count > 0);
289                         }
290                 }
291                 
292 #if ONLY_1_1
293                 [Bindable(true)]
294 #endif          
295                 [DefaultValue(typeof (Unit), "")]
296                 [WebSysDescription ("")]
297                 [WebCategory ("Layout")]
298                 public virtual Unit Height {
299                         get {
300                                 if (style == null) 
301                                         return Unit.Empty;
302                                 
303                                 return style.Height;
304                         }
305                         set {
306                                 ControlStyle.Height = value;
307                         }
308                 }
309
310                 [Browsable (true)]
311                 public virtual new string SkinID
312                 {
313                         get { return base.SkinID; }
314                         set { base.SkinID = value; }
315                 }
316                 
317                 [Browsable(false)]
318                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
319                 [WebSysDescription ("")]
320                 [WebCategory ("Style")]
321                 public CssStyleCollection Style {
322                         get {
323                                 return Attributes.CssStyle;
324                         }
325                 }
326
327                 [DefaultValue((short)0)]
328                 [WebSysDescription ("")]
329                 [WebCategory ("Behavior")]
330                 public virtual short TabIndex {
331                         get {
332                                 return ViewState.GetShort ("TabIndex", 0);
333                         }
334                         set {
335                                 ViewState ["TabIndex"] = value;
336                         }
337                 }
338
339 #if ONLY_1_1
340                 [Bindable(true)]
341 #endif          
342                 [DefaultValue("")]
343                 [Localizable (true)]
344                 [WebSysDescription ("")]
345                 [WebCategory ("Behavior")]
346                 public virtual string ToolTip {
347                         get {
348                                 return ViewState.GetString ("ToolTip", string.Empty);
349                         }
350                         set {
351                                 ViewState ["ToolTip"] = value;
352                         }
353                 }
354
355 #if ONLY_1_1
356                 [Bindable(true)]
357 #endif          
358                 [DefaultValue(typeof (Unit), "")]
359                 [WebSysDescription ("")]
360                 [WebCategory ("Layout")]
361                 public virtual Unit Width {
362                         get {
363                                 if (style == null) 
364                                         return Unit.Empty;
365                                 
366                                 return style.Width;
367                         }
368                         set {
369                                 ControlStyle.Width = value;
370                         }
371                 }
372
373                 [Browsable(false)]
374                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
375                 protected virtual HtmlTextWriterTag TagKey {
376                         get {
377                                 return tag;
378                         }
379                 }
380
381                 [Browsable(false)]
382                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
383                 protected virtual string TagName {
384                         get {
385                                 // do this here to avoid potentially costly lookups on every control
386                                 if (tag_name == null)
387                                         tag_name = HtmlTextWriter.StaticGetTagName (TagKey);
388                                 
389                                 return tag_name;
390                         }
391                 }
392
393                 protected
394                 internal bool IsEnabled 
395                 {
396                         get {
397                                 WebControl wc = this;
398                                 while (wc != null) {
399                                         if (!wc.Enabled)
400                                                 return false;
401                                         wc = wc.Parent as WebControl;
402                                 }
403                                 return true;
404                         }
405                 }
406                 public static string DisabledCssClass {
407                         get;
408                         set;
409                 }
410                 
411                 [Browsable (false)]
412                 public virtual bool SupportsDisabledAttribute {
413                         get { return true; }
414                 }
415                 public void ApplyStyle (Style s) 
416                 {
417                         if (s != null && !s.IsEmpty)
418                                 ControlStyle.CopyFrom(s);
419                 }
420
421                 public void CopyBaseAttributes (WebControl controlSrc) 
422                 {
423                         object o;
424
425                         if (controlSrc == null) 
426                                 return;
427
428                         Enabled = controlSrc.Enabled;
429
430                         o = controlSrc.ViewState ["AccessKey"];
431                         if (o != null)
432                                 ViewState ["AccessKey"] = o;
433
434                         o = controlSrc.ViewState ["TabIndex"];
435                         if (o != null)
436                                 ViewState ["TabIndex"] = o;
437
438                         o = controlSrc.ViewState ["ToolTip"];
439                         if (o != null)
440                                 ViewState ["ToolTip"] = o;
441
442                         if (controlSrc.attributes != null) {
443                                 AttributeCollection attributes = Attributes;
444                                 
445                                 foreach (string s in controlSrc.attributes.Keys)
446                                         attributes [s] = controlSrc.attributes [s];
447                         }
448                 }
449
450                 public void MergeStyle (Style s) 
451                 {
452                         if (s != null && !s.IsEmpty)
453                                 ControlStyle.MergeWith(s);
454                 }
455
456                 public virtual void RenderBeginTag (HtmlTextWriter writer)
457                 {
458                         AddAttributesToRender (writer);
459                         
460                         if (TagKey == HtmlTextWriterTag.Unknown)
461                                 writer.RenderBeginTag (TagName);
462                         else
463                                 writer.RenderBeginTag (TagKey);
464                         
465                 }
466
467                 public virtual void RenderEndTag (HtmlTextWriter writer) 
468                 {
469                         writer.RenderEndTag ();
470                 }
471
472                 static char[] _script_trim_chars = {';'};
473                 internal string BuildScriptAttribute (string name, string tail)
474                 {
475                         AttributeCollection attrs = Attributes;
476                         string attr = attrs [name];
477                         
478                         if (attr == null || attr.Length == 0)
479                                 return tail;
480                         if (attr [attr.Length - 1] == ';')
481                                 attr = attr.TrimEnd (_script_trim_chars);
482                         
483                         attr = String.Concat (attr, ";", tail);
484                         attrs.Remove (name);
485                         
486                         return attr;
487                 }
488                 
489                 internal void AddDisplayStyleAttribute (HtmlTextWriter writer)
490                 {
491                         if (!ControlStyleCreated)
492                                 return;
493
494                         if (!ControlStyle.BorderWidth.IsEmpty ||
495                             (ControlStyle.BorderStyle != BorderStyle.None && ControlStyle.BorderStyle != BorderStyle.NotSet) ||
496                             !ControlStyle.Height.IsEmpty ||
497                             !ControlStyle.Width.IsEmpty)
498                                 writer.AddStyleAttribute (HtmlTextWriterStyle.Display, "inline-block");
499                 }
500                 void RenderDisabled (HtmlTextWriter writer)
501                 {
502                         if (!IsEnabled) {
503                                 if (!SupportsDisabledAttribute)
504                                         ControlStyle.PrependCssClass (DisabledCssClass);
505                                 else
506                                         writer.AddAttribute (HtmlTextWriterAttribute.Disabled, "disabled", false);
507                         }
508
509                 }
510                 
511                 protected virtual void AddAttributesToRender (HtmlTextWriter writer) 
512                 {
513                         RenderDisabled (writer);
514                         if (ID != null)
515                                 writer.AddAttribute(HtmlTextWriterAttribute.Id, ClientID);
516                         if (AccessKey != string.Empty)
517                                 writer.AddAttribute (HtmlTextWriterAttribute.Accesskey, AccessKey);
518                         
519                         if (ToolTip != string.Empty)
520                                 writer.AddAttribute (HtmlTextWriterAttribute.Title, ToolTip);
521
522                         if (TabIndex != 0)
523                                 writer.AddAttribute (HtmlTextWriterAttribute.Tabindex, TabIndex.ToString ());
524
525                         if (style != null && !style.IsEmpty) {
526                                 //unbelievable, but see WebControlTest.RenderBeginTag_BorderWidth_xxx
527                                 if (TagKey == HtmlTextWriterTag.Span)
528                                         AddDisplayStyleAttribute (writer);
529                                 style.AddAttributesToRender(writer, this);
530                         }
531
532                         if (attributes != null)
533                                 foreach(string s in attributes.Keys)
534                                         writer.AddAttribute (s, attributes [s]);
535                 }
536
537                 protected virtual Style CreateControlStyle() 
538                 {
539                         return new Style (ViewState);
540                 }
541
542                 protected override void LoadViewState (object savedState) 
543                 {
544                         if (savedState == null || !(savedState is Pair)) {
545                                 base.LoadViewState (null);
546                                 return;
547                         }
548
549                         Pair pair = (Pair) savedState;
550                         
551                         base.LoadViewState (pair.First);
552                         if (ViewState [System.Web.UI.WebControls.Style.BitStateKey] != null)
553                                 ControlStyle.LoadBitState ();
554
555                         if (pair.Second != null) {
556                                 if (attribute_state == null) {
557                                         attribute_state = new StateBag ();
558                                         if (IsTrackingViewState) 
559                                                 attribute_state.TrackViewState ();
560                                 }
561
562                                 attribute_state.LoadViewState (pair.Second);
563                                 attributes = new AttributeCollection(attribute_state);
564                         }
565
566                         enabled = ViewState.GetBool ("Enabled", enabled);
567                 }
568                 internal virtual string InlinePropertiesSet ()
569                 {
570                         var properties = new List <string> ();
571                         
572                         if (BackColor != Color.Empty)
573                                 properties.Add ("BackColor");
574
575                         if (BorderColor != Color.Empty)
576                                 properties.Add ("BorderColor");
577
578                         if (BorderStyle != BorderStyle.NotSet)
579                                 properties.Add ("BorderStyle");
580
581                         if (BorderWidth != Unit.Empty)
582                                 properties.Add ("BorderWidth");
583
584                         if (CssClass != String.Empty)
585                                 properties.Add ("CssClass");
586
587                         if (ForeColor != Color.Empty)
588                                 properties.Add ("ForeColor");
589
590                         if (Height != Unit.Empty)
591                                 properties.Add ("Height");
592
593                         if (Width != Unit.Empty)
594                                 properties.Add ("Width");
595
596                         if (properties.Count == 0)
597                                 return null;
598
599                         return String.Join (", ", properties);
600                 }
601
602                 internal void VerifyInlinePropertiesNotSet ()
603                 {
604                         var renderOuterTableControl = this as IRenderOuterTable;
605                         if (renderOuterTableControl == null || renderOuterTableControl.RenderOuterTable)
606                                 return;
607
608                         string properties = InlinePropertiesSet ();
609                         if (!String.IsNullOrEmpty (properties)) {
610                                 bool many = properties.IndexOf (',') > -1;
611                                 throw new InvalidOperationException (
612                                         String.Format ("The style propert{0} '{1}' cannot be used while RenderOuterTable is disabled on the {2} control with ID '{3}'",
613                                                        many ? "ies" : "y",
614                                                        properties,
615                                                        GetType ().Name,
616                                                        ID)
617                                 );
618                         }
619                 }
620                 protected internal
621                 override void Render (HtmlTextWriter writer)
622                 {
623                         if (Adapter != null) {
624                                 Adapter.Render(writer);
625                                 return;
626                         }
627                         RenderBeginTag (writer);
628                         RenderContents (writer);
629                         RenderEndTag (writer);
630                 }
631
632                 protected internal
633                 virtual void RenderContents (HtmlTextWriter writer)
634                 {
635                         base.Render (writer);
636                 }
637
638                 protected override object SaveViewState () 
639                 {
640                         if (track_enabled_state)
641                                 ViewState ["Enabled"] = enabled;
642
643                         object view_state;
644                         object attr_view_state = null;
645
646                         if (style != null)
647                                 style.SaveBitState ();
648                         view_state = base.SaveViewState ();
649
650                         if (attribute_state != null)
651                                 attr_view_state = attribute_state.SaveViewState ();
652                 
653                         if (view_state == null && attr_view_state == null)
654                                 return null;
655
656                         return new Pair (view_state, attr_view_state);
657                 }
658
659                 protected override void TrackViewState() 
660                 {
661                         if (style != null)
662                                 style.TrackViewState ();
663
664                         if (attribute_state != null) {
665                                 attribute_state.TrackViewState ();
666                                 attribute_state.SetDirty (true);
667                         }
668
669                         base.TrackViewState ();
670                 }
671
672                 string IAttributeAccessor.GetAttribute (string key) 
673                 {
674                         if (attributes != null)
675                                 return attributes [key];
676
677                         return null;
678                 }
679
680                 void IAttributeAccessor.SetAttribute (string key, string value) 
681                 {
682                         Attributes [key] = value;
683                 }
684         }
685 }