calculate AppRelativeTemplateSourceDirectory from HttpContext when control is not...
[mono.git] / mcs / class / System.Web / System.Web.UI / CssStyleCollection.cs
1 //
2 // System.Web.UI.CssStyleCollection.cs
3 //
4 // Authors:
5 //      Duncan Mak  (duncan@ximian.com)
6 //      Gonzalo Paniagua (gonzalo@ximian.com)
7 //
8 // (C) 2002 Ximian, Inc. (http://www.ximian.com)
9 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System.IO;
32 using System.Collections;
33 using System.Security.Permissions;
34 using System.Text;
35 using System.Collections.Specialized;
36 using System.Globalization;
37
38 namespace System.Web.UI {
39
40         // CAS - no InheritanceDemand here as the class is sealed
41         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
42         public sealed class CssStyleCollection
43         {
44                 StateBag bag;
45                 HybridDictionary style;
46                 StringBuilder _value = new StringBuilder ();
47                 
48                 internal CssStyleCollection ()
49                 {
50 #if NET_2_0
51                         style = new HybridDictionary (true);
52 #else
53                         style = new HybridDictionary (false);
54 #endif
55                 }
56
57                 internal CssStyleCollection (StateBag bag) : this ()
58                 {
59                         this.bag = bag;
60                         if (bag != null && bag [AttributeCollection.StyleAttribute] != null)
61                                 _value.Append (bag [AttributeCollection.StyleAttribute]);
62                         InitFromStyle ();
63                 }
64
65                 void InitFromStyle ()
66                 {
67                         style.Clear ();
68                         if (_value.Length > 0) {
69                                 int startIndex = 0;
70                                 while (startIndex >= 0)
71                                         startIndex = ParseStyle (startIndex);
72                         }
73                 }
74
75                 int ParseStyle (int startIndex)
76                 {
77                         int colon = -1;
78                         for (int i = startIndex; i < _value.Length; i++) {
79                                 if (_value [i] == ':') {
80                                         colon = i;
81                                         break;
82                                 }
83                         }
84                         if (colon == -1 || colon + 1 == _value.Length)
85                                 return -1;
86
87                         string key = _value.ToString (startIndex, colon - startIndex).Trim ();
88
89                         int semicolon = -1;
90                         for (int i = colon + 1; i < _value.Length; i++) {
91                                 if (_value [i] == ';') {
92                                         semicolon = i;
93                                         break;
94                                 }
95                         }
96                         string value;
97                         if (semicolon == -1)
98                                 value = _value.ToString (colon + 1, _value.Length - colon - 1).Trim ();
99                         else
100                                 value = _value.ToString (colon + 1, semicolon - colon - 1).Trim ();
101
102                         style.Add (key, value);
103                         if (semicolon == -1 || semicolon + 1 == _value.Length)
104                                 return -1;
105
106                         return semicolon + 1;
107                 }
108
109                 void BagToValue ()
110                 {
111                         _value.Length = 0;
112                         foreach (string key in style.Keys)
113                                 AppendStyle (_value, key, (string) style [key]);
114                 }
115
116                 static void AppendStyle (StringBuilder sb, string key, string value)
117                 {
118 #if NET_2_0
119                         if (String.Compare (key, "background-image", StringComparison.OrdinalIgnoreCase) == 0 &&
120                             value.Length >= 3 && String.Compare ("url", 0, value, 0, 3, StringComparison.OrdinalIgnoreCase) != 0)
121 #else
122                         if (key == "background-image" && 0 != String.Compare ("url", value.Substring (0, 3), true,
123                                                                               CultureInfo.InvariantCulture))
124 #endif
125                                 sb.AppendFormat ("{0}:url({1});", key, HttpUtility.UrlPathEncode (value));
126                         else
127                                 sb.AppendFormat ("{0}:{1};", key, value);
128                 }
129
130                 public int Count {
131                         get { return style.Count; }
132                 }
133
134                 public string this [string key] {
135                         get { return style [key] as string; }
136                         set { Add (key, value); }
137                 }
138
139                 public ICollection Keys {
140                         get { return style.Keys; }
141                 }
142
143                 public void Add (string key, string value)
144                 {
145                         if (key == null)
146                                 throw new ArgumentNullException ("key");
147
148                         if (value == null) {
149                                 Remove (key);
150                                 return;
151                         }
152
153                         string curr = (string) style [key];
154                         if (curr == null) {
155                                 // just append
156                                 style [key] = value;
157                                 AppendStyle (_value, key, value);
158                         } else if (String.CompareOrdinal (curr, value) == 0) {
159                                 // do nothing
160                                 return;
161                         } else {
162                                 style [key] = value;
163                                 BagToValue ();
164                         }
165
166                         if (bag != null)
167                                 bag [AttributeCollection.StyleAttribute] = _value.ToString ();
168                 }
169
170 #if NET_2_0
171                 public
172 #else
173                 internal
174 #endif
175                 void Add (HtmlTextWriterStyle key, string value)
176                 {
177                         Add (HtmlTextWriter.StaticGetStyleName (key), value);
178                 }
179
180                 public void Clear ()
181                 {
182                         style.Clear ();
183                         SetValueInternal (null);
184                 }
185
186                 public void Remove (string key)
187                 {
188                         if (style [key] == null)
189                                 return;
190                         style.Remove (key);
191                         if (style.Count == 0)
192                                 SetValueInternal (null);
193                         else
194                                 BagToValue ();
195                 }
196 #if NET_2_0
197                 public string this [HtmlTextWriterStyle key] {
198                         get { return style [HtmlTextWriter.StaticGetStyleName (key)] as string; }
199                         set { Add (HtmlTextWriter.StaticGetStyleName (key), value); }
200                 }
201
202                 public void Remove (HtmlTextWriterStyle key)
203                 {
204                         Remove (HtmlTextWriter.StaticGetStyleName (key));
205                 }
206
207                 public
208 #else
209                 internal
210 #endif
211                 string Value {
212                         get { return _value.ToString (); }
213                         set {
214                                 SetValueInternal (value);
215                                 InitFromStyle ();
216                         }
217                 }
218
219                 void SetValueInternal (string value)
220                 {
221                         _value.Length = 0;
222                         if (value != null)
223                                 _value.Append (value);
224                         if (bag != null) {
225                                 if (value == null)
226                                         bag.Remove (AttributeCollection.StyleAttribute);
227                                 else
228                                         bag [AttributeCollection.StyleAttribute] = value;
229                         }
230                 }
231         }
232 }
233