Merge pull request #347 from JamesB7/master
[mono.git] / mcs / class / System / System.Configuration / ApplicationSettingsBase.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, 2006 Novell, Inc (http://www.novell.com)
21 //
22
23 #if CONFIGURATION_DEP && !TARGET_JVM
24 extern alias PrebuiltSystem;
25 using NameValueCollection = PrebuiltSystem.System.Collections.Specialized.NameValueCollection;
26 #endif
27 #if CONFIGURATION_DEP
28 using System.IO;
29 using System.Xml.Serialization;
30 #endif
31
32 using System.ComponentModel;
33 using System.Reflection;
34 using System.Threading;
35 using System.Collections.Specialized;
36
37 namespace System.Configuration {
38
39         public abstract class ApplicationSettingsBase : SettingsBase, INotifyPropertyChanged
40         {
41                 protected ApplicationSettingsBase ()
42                 {
43                         Initialize (Context, Properties, Providers);
44                 }
45
46                 protected ApplicationSettingsBase (IComponent owner)
47                         : this (owner, String.Empty)
48                 {
49                 }
50  
51                 protected ApplicationSettingsBase (string settingsKey)
52                 {
53                         this.settingsKey = settingsKey;
54
55                         Initialize (Context, Properties, Providers);
56                 }
57
58                 protected ApplicationSettingsBase (IComponent owner, 
59                                                    string settingsKey)
60                 {
61                         if (owner == null)
62                                 throw new ArgumentNullException ();
63
64 #if (CONFIGURATION_DEP)
65                         providerService = (ISettingsProviderService)owner.Site.GetService(typeof (ISettingsProviderService));
66 #endif
67                         this.settingsKey = settingsKey;
68
69                         Initialize (Context, Properties, Providers);
70                 }
71
72                 public event PropertyChangedEventHandler PropertyChanged;
73                 public event SettingChangingEventHandler SettingChanging;
74                 public event SettingsLoadedEventHandler SettingsLoaded;
75                 public event SettingsSavingEventHandler SettingsSaving;
76
77                 public object GetPreviousVersion (string propertyName)
78                 {
79                         throw new NotImplementedException ();
80                 }
81
82                 public void Reload ()
83                 {
84 #if (CONFIGURATION_DEP)
85                         foreach (SettingsProvider provider in Providers) {
86                                 IApplicationSettingsProvider iasp = provider as IApplicationSettingsProvider;
87                                 if (iasp != null)
88                                         iasp.Reset (Context);
89                         }
90 #endif
91                 }
92
93                 public void Reset()
94                 {
95 #if (CONFIGURATION_DEP)
96                         // Code bellow is identical to code in Reload().
97                         // foreach (SettingsProvider provider in Providers) {
98                         //         IApplicationSettingsProvider iasp = provider as IApplicationSettingsProvider;
99                         //         if (iasp != null)
100                         //              iasp.Reset (Context);
101                         // }
102                                                 
103                         Reload ();
104 #endif
105                 }
106
107                 public override void Save()
108                 {
109 #if (CONFIGURATION_DEP)
110                         Context.CurrentSettings = this;
111                         /* ew.. this needs to be more efficient */
112                         foreach (SettingsProvider provider in Providers) {
113                                 SettingsPropertyValueCollection cache = new SettingsPropertyValueCollection ();
114
115                                 foreach (SettingsPropertyValue val in PropertyValues) {
116                                         if (val.Property.Provider == provider)
117                                                 cache.Add (val);
118                                 }
119
120                                 if (cache.Count > 0)
121                                         provider.SetPropertyValues (Context, cache);
122                         }
123                         Context.CurrentSettings = null;
124 #endif
125                 }
126
127                 public virtual void Upgrade()
128                 {
129                 }
130
131                 protected virtual void OnPropertyChanged (object sender, 
132                                                           PropertyChangedEventArgs e)
133                 {
134                         if (PropertyChanged != null)
135                                 PropertyChanged (sender, e);
136                 }
137
138                 protected virtual void OnSettingChanging (object sender, 
139                                                           SettingChangingEventArgs e)
140                 {
141                         if (SettingChanging != null)
142                                 SettingChanging (sender, e);
143                 }
144
145                 protected virtual void OnSettingsLoaded (object sender, 
146                                                          SettingsLoadedEventArgs e)
147                 {
148                         if (SettingsLoaded != null)
149                                 SettingsLoaded (sender, e);
150                 }
151
152                 protected virtual void OnSettingsSaving (object sender, 
153                                                          CancelEventArgs e)
154                 {
155                         if (SettingsSaving != null)
156                                 SettingsSaving (sender, e);
157                 }
158
159                 [Browsable (false)]
160                 public override SettingsContext Context {
161                         get {
162                                 if (IsSynchronized)
163                                         Monitor.Enter (this);
164
165                                 try {
166                                         if (context == null) {
167                                                 context = new SettingsContext ();
168                                                 context ["SettingsKey"] = "";
169                                                 Type type = GetType ();
170                                                 context ["GroupName"] = type.FullName;
171                                                 context ["SettingsClassType"] = type;
172                                         }
173
174                                         return context;
175                                 } finally {
176                                         if (IsSynchronized)
177                                                 Monitor.Exit (this);
178                                 }
179                         }
180                 }
181
182                 void CacheValuesByProvider (SettingsProvider provider)
183                 {
184                         SettingsPropertyCollection col = new SettingsPropertyCollection ();
185
186                         foreach (SettingsProperty p in Properties) {
187                                 if (p.Provider == provider)
188                                         col.Add (p);
189                         }
190
191                         if (col.Count > 0) {
192                                 SettingsPropertyValueCollection vals = provider.GetPropertyValues (Context, col);
193                                 PropertyValues.Add (vals);
194                         }
195
196                         OnSettingsLoaded (this, new SettingsLoadedEventArgs (provider));
197                 }
198
199                 void InitializeSettings (SettingsPropertyCollection settings)
200                 {
201                 }
202
203                 object GetPropertyValue (string propertyName)
204                 {
205                         SettingsProperty prop = Properties [ propertyName ];
206
207                         if (prop == null)
208                                 throw new SettingsPropertyNotFoundException (propertyName);
209
210                         if (propertyValues == null)
211                                 InitializeSettings (Properties);
212
213                         if (PropertyValues [ propertyName ] == null)
214                                 CacheValuesByProvider (prop.Provider);
215
216                         return PropertyValues [ propertyName ].PropertyValue;
217                 }
218
219                 [MonoTODO]
220                 public override object this [ string propertyName ] {
221                         get {
222                                 if (IsSynchronized) {
223                                         lock (this) {
224                                                 return GetPropertyValue (propertyName);
225                                         }
226                                 }
227
228                                 return GetPropertyValue (propertyName);
229                         }
230                         set {
231                                 SettingsProperty prop = Properties [ propertyName ];
232
233                                 if (prop == null)
234                                         throw new SettingsPropertyNotFoundException (propertyName);
235
236                                 if (prop.IsReadOnly)
237                                         throw new SettingsPropertyIsReadOnlyException (propertyName);
238
239                                 /* XXX check the type of the property vs the type of @value */
240                                 if (value != null &&
241                                     !prop.PropertyType.IsAssignableFrom (value.GetType()))
242                                         throw new SettingsPropertyWrongTypeException (propertyName);
243
244                                 if (PropertyValues [ propertyName ] == null)
245                                         CacheValuesByProvider (prop.Provider);
246
247                                 SettingChangingEventArgs changing_args = new SettingChangingEventArgs (propertyName,
248                                                                                                        GetType().FullName,
249                                                                                                        settingsKey,
250                                                                                                        value,
251                                                                                                        false);
252
253                                 OnSettingChanging (this, changing_args);
254
255                                 if (changing_args.Cancel == false) {
256                                         /* actually set the value */
257                                         PropertyValues [ propertyName ].PropertyValue = value;
258
259                                         /* then emit PropertyChanged */
260                                         OnPropertyChanged (this, new PropertyChangedEventArgs (propertyName));
261                                 }
262                         }
263                 }
264
265 #if (CONFIGURATION_DEP)
266                 [Browsable (false)]
267                 public override SettingsPropertyCollection Properties {
268                         get {
269                                 if (IsSynchronized)
270                                         Monitor.Enter (this);
271
272                                 try {
273                                         if (properties == null) {
274                                                 SettingsProvider local_provider = null;
275
276                                                 properties = new SettingsPropertyCollection ();
277
278                                                 Type this_type = GetType();
279                                                 SettingsProviderAttribute[] provider_attrs = (SettingsProviderAttribute[])this_type.GetCustomAttributes (typeof (SettingsProviderAttribute), false);;
280                                                 if (provider_attrs != null && provider_attrs.Length != 0) {
281                                                         Type provider_type = Type.GetType (provider_attrs[0].ProviderTypeName);
282                                                         SettingsProvider provider = (SettingsProvider) Activator.CreateInstance (provider_type);
283                                                         provider.Initialize (null, null);
284                                                         if (provider != null && Providers [provider.Name] == null) {
285                                                                 Providers.Add (provider);
286                                                                 local_provider = provider;
287                                                         }
288                                                 }
289
290                                                 PropertyInfo[] type_props = this_type.GetProperties ();
291                                                 foreach (PropertyInfo prop in type_props) { // only public properties
292                                                         SettingAttribute[] setting_attrs = (SettingAttribute[])prop.GetCustomAttributes (typeof (SettingAttribute), false);
293                                                         if (setting_attrs == null || setting_attrs.Length == 0)
294                                                                 continue;
295                                                         CreateSettingsProperty (prop, properties, ref local_provider);
296                                                 }
297                                         }
298
299                                         return properties;
300                                 } finally {
301                                         if (IsSynchronized)
302                                                 Monitor.Exit (this);
303                                 }
304                         }
305                 }
306
307                 void CreateSettingsProperty (PropertyInfo prop, SettingsPropertyCollection properties, ref SettingsProvider local_provider)
308                 {
309                         SettingsAttributeDictionary dict = new SettingsAttributeDictionary ();
310                         SettingsProvider provider = null;
311                         object defaultValue = null;
312                         SettingsSerializeAs serializeAs = SettingsSerializeAs.String;
313                         bool explicitSerializeAs = false;
314
315                         foreach (Attribute a in prop.GetCustomAttributes (false)) {
316                                 /* the attributes we handle natively here */
317                                 if (a is SettingsProviderAttribute) {
318                                         Type provider_type = Type.GetType (((SettingsProviderAttribute)a).ProviderTypeName);
319                                         provider = (SettingsProvider) Activator.CreateInstance (provider_type);
320                                         provider.Initialize (null, null);
321                                 }
322                                 else if (a is DefaultSettingValueAttribute) {
323                                         defaultValue = ((DefaultSettingValueAttribute)a).Value;
324                                 }
325                                 else if (a is SettingsSerializeAsAttribute) {
326                                         serializeAs = ((SettingsSerializeAsAttribute)a).SerializeAs;
327                                         explicitSerializeAs = true;
328                                 }
329                                 else if (a is ApplicationScopedSettingAttribute ||
330                                          a is UserScopedSettingAttribute) {
331                                         dict.Add (a.GetType(), a);
332                                 }
333                                 else {
334                                         dict.Add (a.GetType(), a);
335                                 }
336                         }
337
338                         if (!explicitSerializeAs) {
339                                 // DefaultValue is a string and if we can't convert from string to the 
340                                 // property type then the only other option left is for the string to 
341                                 // be XML.
342                                 //
343                                 TypeConverter converter = TypeDescriptor.GetConverter (prop.PropertyType);
344                                 if (converter != null && 
345                                     (!converter.CanConvertFrom (typeof (string)) || 
346                                      !converter.CanConvertTo (typeof (string))))
347                                         serializeAs = SettingsSerializeAs.Xml;
348                         }
349
350                         SettingsProperty setting =
351                                 new SettingsProperty (prop.Name, prop.PropertyType, provider, false /* XXX */,
352                                                       defaultValue /* XXX always a string? */, serializeAs, dict,
353                                                       false, false);
354
355
356                         if (providerService != null)
357                                 setting.Provider = providerService.GetSettingsProvider (setting);
358
359                         if (provider == null) {
360                                 if (local_provider == null) {
361                                         local_provider = new LocalFileSettingsProvider () as SettingsProvider;
362                                         local_provider.Initialize (null, null);
363                                 }
364                                 setting.Provider = local_provider;
365                                 // .NET ends up to set this to providers.
366                                 provider = local_provider;
367                         }
368
369                         if (provider != null) {
370                                 /* make sure we're using the same instance of a
371                                    given provider across multiple properties */
372                                 SettingsProvider p = Providers[provider.Name];
373                                 if (p != null)
374                                         setting.Provider = p;
375                         }
376
377                         properties.Add (setting);
378
379                         if (setting.Provider != null && Providers [setting.Provider.Name] == null)
380                                 Providers.Add (setting.Provider);
381                 }
382 #endif
383
384                 [Browsable (false)]
385                 public override SettingsPropertyValueCollection PropertyValues {
386                         get {
387                                 if (IsSynchronized)
388                                         Monitor.Enter (this);
389
390                                 try {
391                                         if (propertyValues == null) {
392                                                 propertyValues = new SettingsPropertyValueCollection ();
393                                         }
394
395                                         return propertyValues;
396                                 } finally {
397                                         if (IsSynchronized)
398                                                 Monitor.Exit (this);
399                                 }
400                         }
401                 }
402
403                 [Browsable (false)]
404                 public override SettingsProviderCollection Providers {
405                         get {
406                                 if (IsSynchronized)
407                                         Monitor.Enter (this);
408
409                                 try {
410                                         if (providers == null)
411                                                 providers = new SettingsProviderCollection ();
412
413                                         return providers;
414                                 } finally {
415                                         if (IsSynchronized)
416                                                 Monitor.Exit (this);
417                                 }
418                         }
419                 }
420
421                 [Browsable (false)]
422                 public string SettingsKey {
423                         get {
424                                 return settingsKey;
425                         }
426                         set {
427                                 settingsKey = value;
428                         }
429                 }
430
431                 string settingsKey;
432                 SettingsContext context;
433 #if (CONFIGURATION_DEP)         
434                 SettingsPropertyCollection properties;
435                 ISettingsProviderService providerService;
436 #endif
437                 SettingsPropertyValueCollection propertyValues;
438                 SettingsProviderCollection providers;
439         }
440
441 }
442