Flush
[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                                                 LocalFileSettingsProvider local_provider = null;
276
277                                                 properties = new SettingsPropertyCollection ();
278
279                                                 foreach (PropertyInfo prop in GetType ().GetProperties ()) { // only public properties
280                                                         SettingAttribute[] setting_attrs = (SettingAttribute[])prop.GetCustomAttributes (typeof (SettingAttribute), false);
281                                                         if (setting_attrs == null || setting_attrs.Length == 0)
282                                                                 continue;
283                                                         CreateSettingsProperty (prop, properties, ref local_provider);
284                                                 }
285                                         }
286
287                                         return properties;
288                                 } finally {
289                                         if (IsSynchronized)
290                                                 Monitor.Exit (this);
291                                 }
292                         }
293                 }
294
295                 void CreateSettingsProperty (PropertyInfo prop, SettingsPropertyCollection properties, ref LocalFileSettingsProvider local_provider)
296                 {
297                         SettingsAttributeDictionary dict = new SettingsAttributeDictionary ();
298                         SettingsProvider provider = null;
299                         object defaultValue = null;
300                         SettingsSerializeAs serializeAs = SettingsSerializeAs.String;
301                         bool explicitSerializeAs = false;
302
303                         foreach (Attribute a in prop.GetCustomAttributes (false)) {
304                                 /* the attributes we handle natively here */
305                                 if (a is SettingsProviderAttribute) {
306                                         Type provider_type = Type.GetType (((SettingsProviderAttribute)a).ProviderTypeName);
307                                         provider = (SettingsProvider) Activator.CreateInstance (provider_type);
308                                         provider.Initialize (null, null);
309                                 }
310                                 else if (a is DefaultSettingValueAttribute) {
311                                         defaultValue = ((DefaultSettingValueAttribute)a).Value;
312                                 }
313                                 else if (a is SettingsSerializeAsAttribute) {
314                                         serializeAs = ((SettingsSerializeAsAttribute)a).SerializeAs;
315                                         explicitSerializeAs = true;
316                                 }
317                                 else if (a is ApplicationScopedSettingAttribute ||
318                                          a is UserScopedSettingAttribute) {
319                                         dict.Add (a.GetType(), a);
320                                 }
321                                 else {
322                                         dict.Add (a.GetType(), a);
323                                 }
324                         }
325
326                         if (!explicitSerializeAs) {
327                                 // DefaultValue is a string and if we can't convert from string to the 
328                                 // property type then the only other option left is for the string to 
329                                 // be XML.
330                                 //
331                                 TypeConverter converter = TypeDescriptor.GetConverter (prop.PropertyType);
332                                 if (converter != null && 
333                                     (!converter.CanConvertFrom (typeof (string)) || 
334                                      !converter.CanConvertTo (typeof (string))))
335                                         serializeAs = SettingsSerializeAs.Xml;
336                         }
337
338                         SettingsProperty setting =
339                                 new SettingsProperty (prop.Name, prop.PropertyType, provider, false /* XXX */,
340                                                       defaultValue /* XXX always a string? */, serializeAs, dict,
341                                                       false, false);
342
343
344                         if (providerService != null)
345                                 setting.Provider = providerService.GetSettingsProvider (setting);
346
347                         if (provider == null) {
348                                 if (local_provider == null) {
349                                         local_provider = new LocalFileSettingsProvider ();
350                                         local_provider.Initialize (null, null);
351                                 }
352                                 setting.Provider = local_provider;
353                                 // .NET ends up to set this to providers.
354                                 provider = local_provider;
355                         }
356
357                         if (provider != null) {
358                                 /* make sure we're using the same instance of a
359                                    given provider across multiple properties */
360                                 SettingsProvider p = Providers[provider.Name];
361                                 if (p != null)
362                                         setting.Provider = p;
363                         }
364
365                         properties.Add (setting);
366
367                         if (setting.Provider != null && Providers [setting.Provider.Name] == null)
368                                 Providers.Add (setting.Provider);
369                 }
370 #endif
371
372                 [Browsable (false)]
373                 public override SettingsPropertyValueCollection PropertyValues {
374                         get {
375                                 if (IsSynchronized)
376                                         Monitor.Enter (this);
377
378                                 try {
379                                         if (propertyValues == null) {
380                                                 propertyValues = new SettingsPropertyValueCollection ();
381                                         }
382
383                                         return propertyValues;
384                                 } finally {
385                                         if (IsSynchronized)
386                                                 Monitor.Exit (this);
387                                 }
388                         }
389                 }
390
391                 [Browsable (false)]
392                 public override SettingsProviderCollection Providers {
393                         get {
394                                 if (IsSynchronized)
395                                         Monitor.Enter (this);
396
397                                 try {
398                                         if (providers == null)
399                                                 providers = new SettingsProviderCollection ();
400
401                                         return providers;
402                                 } finally {
403                                         if (IsSynchronized)
404                                                 Monitor.Exit (this);
405                                 }
406                         }
407                 }
408
409                 [Browsable (false)]
410                 public string SettingsKey {
411                         get {
412                                 return settingsKey;
413                         }
414                         set {
415                                 settingsKey = value;
416                         }
417                 }
418
419                 string settingsKey;
420                 SettingsContext context;
421 #if (CONFIGURATION_DEP)         
422                 SettingsPropertyCollection properties;
423                 ISettingsProviderService providerService;
424 #endif
425                 SettingsPropertyValueCollection propertyValues;
426                 SettingsProviderCollection providers;
427         }
428
429 }
430 #endif
431