Merge pull request #268 from pcc/menudeactivate
[mono.git] / mcs / class / System.Configuration / System.Configuration / SectionGroupInfo.cs
1 //
2 // System.Configuration.SectionGroupInfo.cs
3 //
4 // Authors:
5 //      Lluis Sanchez (lluis@novell.com)
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining
8 // a copy of this software and associated documentation files (the
9 // "Software"), to deal in the Software without restriction, including
10 // without limitation the rights to use, copy, modify, merge, publish,
11 // distribute, sublicense, and/or sell copies of the Software, and to
12 // permit persons to whom the Software is furnished to do so, subject to
13 // the following conditions:
14 // 
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
17 // 
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 //
26 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
27 //
28
29 using System;
30 using System.Collections;
31 using System.Collections.Specialized;
32 using System.Xml;
33 using System.IO;
34 using System.Text;
35
36 namespace System.Configuration
37 {
38         internal class SectionGroupInfo: ConfigInfo
39         {
40                 bool modified;
41                 ConfigInfoCollection sections;
42                 ConfigInfoCollection groups;
43                 static ConfigInfoCollection emptyList = new ConfigInfoCollection ();
44
45                 public SectionGroupInfo ()
46                 {
47                         Type = typeof (ConfigurationSectionGroup);
48                 }
49                 
50                 public SectionGroupInfo (string groupName, string typeName)
51                 {
52                         Name = groupName;
53                         TypeName = typeName;
54                 }
55                 
56                 public void AddChild (ConfigInfo data)
57                 {
58                         modified = true;
59                         data.Parent = this;
60                         if (data is SectionInfo) {
61                                 if (sections == null) sections = new ConfigInfoCollection ();
62                                 sections [data.Name] = data;
63                         }
64                         else {
65                                 if (groups == null) groups = new ConfigInfoCollection ();
66                                 groups [data.Name] = data;
67                         }
68                 }
69                 
70                 public void Clear ()
71                 {
72                         modified = true;
73                         if (sections != null) sections.Clear ();
74                         if (groups != null) groups.Clear ();
75                 }
76                 
77                 public bool HasChild (string name)
78                 {
79                         if (sections != null && sections [name] != null) return true;
80                         return (groups != null && groups [name] != null);
81                 }
82                 
83                 public void RemoveChild (string name)
84                 {
85                         modified = true;
86                         if (sections != null)
87                                 sections.Remove (name);
88                         if (groups != null)
89                                 groups.Remove (name);
90                 }
91                 
92                 public SectionInfo GetChildSection (string name)
93                 {
94                         if (sections != null)
95                                 return sections [name] as SectionInfo;
96                         else
97                                 return null;
98                 }
99                 
100                 public SectionGroupInfo GetChildGroup (string name)
101                 {
102                         if (groups != null)
103                                 return groups [name] as SectionGroupInfo;
104                         else
105                                 return null;
106                 }
107                 
108                 public ConfigInfoCollection Sections
109                 {
110                         get { if (sections == null) return emptyList; else return sections; }
111                 }
112                 
113                 public ConfigInfoCollection Groups
114                 {
115                         get { if (groups == null) return emptyList; else return groups; }
116                 }
117                 
118                 public override bool HasDataContent (Configuration config)
119                 {
120                         foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
121                                 foreach (string key in col) {
122                                         ConfigInfo cinfo = col [key];
123                                         if (cinfo.HasDataContent (config))
124                                                 return true;
125                                 }
126                         }
127                         return false;
128                 }
129                 
130                 public override bool HasConfigContent (Configuration cfg)
131                 {
132                         if (StreamName == cfg.FileName) return true;
133                         foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
134                                 foreach (string key in col) {
135                                         ConfigInfo cinfo = col [key];
136                                         if (cinfo.HasConfigContent (cfg))
137                                                 return true;
138                                 }
139                         }
140                         return false;
141                 }
142                 
143                 public override void ReadConfig (Configuration cfg, string streamName, XmlReader reader)
144                 {
145                         StreamName = streamName;
146                         ConfigHost = cfg.ConfigHost;
147                         
148                         if (reader.LocalName != "configSections")
149                         {
150                                 while (reader.MoveToNextAttribute ()) {
151                                         if (reader.Name == "name")
152                                                 Name = reader.Value;
153                                         else if (reader.Name == "type") {
154                                                 TypeName = reader.Value;
155                                                 Type = null;
156                                         }
157                                         else
158                                                 ThrowException ("Unrecognized attribute", reader);
159                                 }
160                                 
161                                 if (Name == null)
162                                         ThrowException ("sectionGroup must have a 'name' attribute", reader);
163         
164                                 if (Name == "location")
165                                         ThrowException ("location is a reserved section name", reader);
166                         }
167                         
168                         if (TypeName == null)
169                                 TypeName = "System.Configuration.ConfigurationSectionGroup";
170                         
171                         if (reader.IsEmptyElement) {
172                                 reader.Skip ();
173                                 return;
174                         }
175                         
176                         reader.ReadStartElement ();
177                         reader.MoveToContent ();
178                         
179                         while (reader.NodeType != XmlNodeType.EndElement)
180                         {
181                                 if (reader.NodeType != XmlNodeType.Element) {
182                                         reader.Skip ();
183                                         continue;
184                                 }
185                                 
186                                 string name = reader.LocalName;
187                                 ConfigInfo cinfo = null;
188                                 
189                                 if (name == "remove") {
190                                         ReadRemoveSection (reader);
191                                         continue;
192                                 }
193
194                                 if (name == "clear") {
195                                         if (reader.HasAttributes)
196                                                 ThrowException ("Unrecognized attribute.", reader);
197
198                                         Clear ();
199                                         reader.Skip ();
200                                         continue;
201                                 }
202
203                                 if (name == "section")
204                                         cinfo = new SectionInfo ();
205                                 else if (name == "sectionGroup") {
206                                         cinfo = new SectionGroupInfo ();
207                                 } else
208                                         ThrowException ("Unrecognized element: " + reader.Name, reader);
209                                         
210                                 cinfo.ReadConfig (cfg, streamName, reader);
211                                 ConfigInfo actInfo = Groups [cinfo.Name];
212                                 if (actInfo == null) actInfo = Sections [cinfo.Name];
213                                 
214                                 if (actInfo != null) {
215                                         if (actInfo.GetType () != cinfo.GetType ())
216                                                 ThrowException ("A section or section group named '" + cinfo.Name + "' already exists", reader);
217                                         // Merge all the new data
218                                         actInfo.Merge (cinfo);
219                                         
220                                         // Make sure that this section is saved in this configuration file:
221                                         actInfo.StreamName = streamName;
222                                 }
223                                 else
224                                         AddChild (cinfo);
225                         }
226                         
227                         reader.ReadEndElement ();
228                 }
229                 
230                 public override void WriteConfig (Configuration cfg, XmlWriter writer, ConfigurationSaveMode mode)
231                 {
232                         if (Name != null) {
233                                 writer.WriteStartElement ("sectionGroup");
234                                 writer.WriteAttributeString ("name", Name);
235                                 if (TypeName != null && TypeName != "" && TypeName != "System.Configuration.ConfigurationSectionGroup")
236                                         writer.WriteAttributeString ("type", TypeName);
237                         }
238                         else
239                                 writer.WriteStartElement ("configSections");
240                         
241                         foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
242                                 foreach (string key in col) {
243                                         ConfigInfo cinfo = col [key];
244                                         if (cinfo.HasConfigContent (cfg))
245                                                 cinfo.WriteConfig (cfg, writer, mode);
246                                 }
247                         }
248                         
249                         writer.WriteEndElement ();
250                 }
251
252                 private void ReadRemoveSection (XmlReader reader)
253                 {
254                         if (!reader.MoveToNextAttribute () || reader.Name != "name")
255                                 ThrowException ("Unrecognized attribute.", reader);
256
257                         string removeValue = reader.Value;
258                         if (String.IsNullOrEmpty (removeValue))
259                                 ThrowException ("Empty name to remove", reader);
260
261                         reader.MoveToElement ();
262
263                         if (!HasChild (removeValue))
264                                 ThrowException ("No factory for " + removeValue, reader);
265
266                         RemoveChild (removeValue);
267                         reader.Skip ();
268                 }
269
270                 public void ReadRootData (XmlReader reader, Configuration config, bool overrideAllowed)
271                 {
272                         reader.MoveToContent ();
273                         ReadContent (reader, config, overrideAllowed, true);
274                 }
275                 
276                 public override void ReadData (Configuration config, XmlReader reader, bool overrideAllowed)
277                 {
278                         reader.MoveToContent ();
279                         if (!reader.IsEmptyElement) {
280                                 reader.ReadStartElement ();
281                                 ReadContent (reader, config, overrideAllowed, false);
282                                 reader.MoveToContent ();
283                                 reader.ReadEndElement ();
284                         } else
285                                 reader.Read ();
286                 }
287                 
288                 void ReadContent (XmlReader reader, Configuration config, bool overrideAllowed, bool root)
289                 {
290                         while (reader.NodeType != XmlNodeType.EndElement && reader.NodeType != XmlNodeType.None) {
291                                 if (reader.NodeType != XmlNodeType.Element) {
292                                         reader.Skip ();
293                                         continue;
294                                 }
295
296                                 if (reader.LocalName == "dllmap") {
297                                         reader.Skip ();
298                                         continue;
299                                 }
300
301                                 if (reader.LocalName == "location") {
302                                         if (!root)
303                                                 ThrowException ("<location> elements are only allowed in <configuration> elements.", reader);
304
305                                         string allowOverrideAttr = reader.GetAttribute ("allowOverride");
306                                         bool allowOverride = allowOverrideAttr == null || allowOverrideAttr.Length == 0 || bool.Parse (allowOverrideAttr);
307                                         string path = reader.GetAttribute ("path");
308                                         if (path != null && path.Length > 0) {
309                                                 string xml = reader.ReadOuterXml ();
310                                                 string[] pathList = path.Split (',');
311                                                 string tpath;
312                                                 foreach (string p in pathList) {
313                                                         tpath = p.Trim ();
314                                                         if (config.Locations.Find (tpath) != null)
315                                                                 ThrowException ("Sections must only appear once per config file.", reader);
316                                                         
317                                                         ConfigurationLocation loc = new ConfigurationLocation (tpath, xml, config, allowOverride);
318                                                         config.Locations.Add (loc);
319                                                 }
320                                         } else {
321                                                 ReadData (config, reader, allowOverride);
322                                         }
323                                         continue;
324                                 }
325                         
326                                 ConfigInfo data = GetConfigInfo (reader, this);
327                                 if (data != null)
328                                         data.ReadData (config, reader, overrideAllowed);
329                                 else
330                                         ThrowException ("Unrecognized configuration section <" + reader.LocalName + ">", reader);
331                         }
332                 }
333
334                 ConfigInfo GetConfigInfo (XmlReader reader, SectionGroupInfo current)
335                 {
336                         ConfigInfo data = null;
337                         if (current.sections != null)
338                                 data = current.sections [reader.LocalName];
339                         if (data != null)
340                                 return data;
341                         if (current.groups != null)
342                                 data = current.groups [reader.LocalName];
343                         if (data != null)
344                                 return data;
345                         if (current.groups == null)
346                                 return null;
347                         // It might be a section in descendant sectionGroups
348                         foreach (string key in current.groups.AllKeys) {
349                                 data = GetConfigInfo (reader, (SectionGroupInfo) current.groups [key]);
350                                 if (data != null)
351                                         return data;
352                         }
353                         
354                         // It might be in the root section group
355                         return null;
356                 }
357
358                 internal override void Merge (ConfigInfo newData)
359                 {
360                         SectionGroupInfo data = newData as SectionGroupInfo;
361                         if (data == null)
362                                 return;
363                         ConfigInfo actInfo;
364                         if (data.sections != null && data.sections.Count > 0)
365                                 foreach (string key in data.sections.AllKeys) {
366                                         actInfo = sections[key];
367                                         if (actInfo != null)
368                                                 continue;
369                                         sections.Add (key, data.sections[key]);
370                                 }
371                         
372                         if (data.groups != null && data.sections != null && data.sections.Count > 0)
373                                 foreach (string key in data.groups.AllKeys) {
374                                         actInfo = groups[key];
375                                         if (actInfo != null)
376                                                 continue;
377                                         groups.Add (key, data.groups[key]);
378                                 }
379                 }
380                 
381                 public void WriteRootData (XmlWriter writer, Configuration config, ConfigurationSaveMode mode)
382                 {
383                         WriteContent (writer, config, mode, false);
384                 }
385                 
386                 public override void WriteData (Configuration config, XmlWriter writer, ConfigurationSaveMode mode)
387                 {
388                         writer.WriteStartElement (Name);
389                         WriteContent (writer, config, mode, true);
390                         writer.WriteEndElement ();
391                 }
392                 
393                 public void WriteContent (XmlWriter writer, Configuration config, ConfigurationSaveMode mode, bool writeElem)
394                 {
395                         foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
396                                 foreach (string key in col) {
397                                         ConfigInfo cinfo = col [key];
398                                         if (cinfo.HasDataContent (config))
399                                                 cinfo.WriteData (config, writer, mode);
400                                 }
401                         }
402                 }
403
404                 internal override bool HasValues (Configuration config, ConfigurationSaveMode mode)
405                 {
406                         if (modified && (mode == ConfigurationSaveMode.Modified))
407                                 return true;
408
409                         foreach (ConfigInfoCollection col in new object[] { Sections, Groups}) {
410                                 foreach (string key in col) {
411                                         ConfigInfo cinfo = col [key];
412                                         if (cinfo.HasValues (config, mode))
413                                                 return true;
414                                 }
415                         }
416
417                         return false;
418                 }
419
420                 internal override void ResetModified (Configuration config)
421                 {
422                         modified = false;
423                         foreach (ConfigInfoCollection col in new object[] { Sections, Groups}) {
424                                 foreach (string key in col) {
425                                         ConfigInfo cinfo = col [key];
426                                         cinfo.ResetModified (config);
427                                 }
428                         }
429                 }
430         }
431         
432         internal class ConfigInfoCollection : NameObjectCollectionBase
433         {
434                 public ConfigInfoCollection ()
435                         : base (StringComparer.Ordinal)
436                 {
437                 }
438
439                 public ICollection AllKeys
440                 {
441                         get { return Keys; }
442                 }
443                 
444                 public ConfigInfo this [string name]
445                 {
446                         get { return (ConfigInfo) BaseGet (name); }
447                         set { BaseSet (name, value); }
448                 }
449         
450                 public ConfigInfo this [int index]
451                 {
452                         get { return (ConfigInfo) BaseGet (index); }
453                         set { BaseSet (index, value); }
454                 }
455                 
456                 public void Add (string name, ConfigInfo config)
457                 {
458                         BaseAdd (name, config);
459                 }
460                 
461                 public void Clear ()
462                 {
463                         BaseClear ();
464                 }
465                 
466                 public string GetKey (int index)
467                 {
468                         return BaseGetKey (index);
469                 }
470                 
471                 public void Remove (string name)
472                 {
473                         BaseRemove (name);
474                 }
475                 
476                 public void RemoveAt (int index)
477                 {
478                         BaseRemoveAt (index);
479                 }
480         }
481 }
482