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