88cf9dd529fbde7c115f811b338425858b6a89e8
[mono.git] / mcs / class / System.Design / System.ComponentModel.Design.Serialization / DesignerSerializationManager.cs
1 //
2 // System.ComponentModel.Design.Serialization.DesignerSerializationManager
3 //
4 // Authors:      
5 //        Ivan N. Zlatev (contact i-nZ.net)
6 //
7 // (C) 2007 Ivan N. Zlatev
8
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 #if NET_2_0
31
32 using System;
33 using System.Collections;
34 using System.Collections.Generic;
35 using System.Reflection;
36 using System.ComponentModel;
37 using System.ComponentModel.Design;
38
39
40
41 namespace System.ComponentModel.Design.Serialization
42 {
43         
44         public class DesignerSerializationManager : IDesignerSerializationManager, IServiceProvider
45         {
46                 
47                 private class Session : IDisposable
48                 {
49                         
50                         private DesignerSerializationManager _manager;
51                         
52                         public Session (DesignerSerializationManager manager)
53                         {
54                                 _manager = manager;
55                         }
56                         
57                         public void Dispose ()
58                         {
59                                 _manager.OnSessionDisposed (EventArgs.Empty);
60                         }
61                 }
62
63                 
64                 
65                 public DesignerSerializationManager () : this (null)
66                 {
67                 }
68                 
69                 // This constructor sets the PreserveNames and ValidateRecycledTypes properties to true.
70                 //
71                 public DesignerSerializationManager (IServiceProvider provider)
72                 {
73                         _serviceProvider = provider;
74                         _preserveNames = true;
75                         _validateRecycledTypes = true;
76                 }
77                 
78                 private IServiceProvider _serviceProvider;
79                 private bool _preserveNames = false;
80                 private bool _validateRecycledTypes = false;
81                 private bool _recycleInstances = false;
82                 private IContainer _designerContainer = null;
83                 private object _propertyProvider = null;
84                 private Session _session = null;
85                 private ArrayList _errors = null;
86                 private List <IDesignerSerializationProvider> _serializationProviders;
87                 private Dictionary <Type, object> _serializersCache = null; // componentType - serializer instance
88                 private Dictionary <string, object> _instancesByNameCache = null; // name - instance
89                 private Dictionary <object, string> _instancesByValueCache = null; // instance - name
90                 private ContextStack _contextStack = null;
91                 
92                 
93                 public bool RecycleInstances {
94                         get { return _recycleInstances; }
95                         set {
96                                 VerifyNotInSession ();
97                                 _recycleInstances = value; 
98                         }
99                 }
100                 
101                 public bool PreserveNames {
102                         get { return _preserveNames; }
103                         set {
104                                 VerifyNotInSession ();
105                                 _preserveNames = value; 
106                         }
107                 }
108                 
109                 public bool ValidateRecycledTypes {
110                         get { return _validateRecycledTypes; }
111                         set {
112                                 VerifyNotInSession ();
113                                 _validateRecycledTypes = value; 
114                         }
115                 }
116                 
117                 public IContainer Container { 
118                         get {
119                                 if (_designerContainer == null) {
120                                         _designerContainer = (this.GetService (typeof (IDesignerHost)) as IDesignerHost).Container;
121                                 }
122                                 return _designerContainer;
123                         }
124                         set{
125                                 VerifyNotInSession ();
126                                 _designerContainer = value;
127                         }
128                 }
129                 
130                 public object PropertyProvider {
131                         get { return _propertyProvider; }
132                         set { _propertyProvider = value; }
133                 }
134                 
135                 public IList Errors {
136                         get { return _errors; }
137                 }
138                 
139                 public event EventHandler SessionDisposed;
140                 public event EventHandler SessionCreated;
141                 
142                 protected virtual void OnSessionCreated (EventArgs e)
143                 {
144                         if (SessionCreated != null) {
145                                 SessionCreated (this, e);
146                         }
147                 }
148                         
149                 // For behaviour description:
150                 //
151                 // http://msdn2.microsoft.com/en-us/library/system.componentmodel.design.serialization.designerserializationmanager.validaterecycledtypes.aspx
152                 // http://msdn2.microsoft.com/en-us/library/system.componentmodel.design.serialization.designerserializationmanager.preservenames.aspx
153                 //
154                 protected virtual object CreateInstance (Type type, ICollection arguments, string name, bool addToContainer)
155                 {
156                         VerifyInSession ();
157                         
158                         object instance = null;
159
160                         if (name != null && _recycleInstances) {
161                                 _instancesByNameCache.TryGetValue (name, out instance);
162                                 if (instance != null && _validateRecycledTypes) {
163                                         if (instance.GetType () != type)
164                                                 instance = null;
165                                 }
166                         }
167                         
168                         if (instance == null || !_recycleInstances) {
169                                 instance = this.CreateInstance (type, arguments);
170                         }
171                 
172                         if (addToContainer && instance != null && this.Container != null && typeof (IComponent).IsAssignableFrom (type)) {
173                                 if (_preserveNames) {
174                                         this.Container.Add ((IComponent) instance, name);
175                                 }
176                                 else {
177                                         if (name != null && this.Container.Components[name] != null) {
178                                                 this.Container.Add ((IComponent) instance);
179                                         }
180                                         else {
181                                                 this.Container.Add ((IComponent) instance, name);
182                                         }
183                                 }
184                                 ISite site = ((IComponent)instance).Site; // get the name from the site in case a name has been generated.
185                                 if (site != null)
186                                         name = site.Name;
187                         }
188                         
189                         if (instance != null && name != null) {
190                                 _instancesByNameCache[name] = instance;
191                                 _instancesByValueCache[instance] = name;
192                         }
193                         
194                         return instance;
195                 }
196
197                 // Invokes the constructor that matches the arguments
198                 //
199                 private object CreateInstance (Type type, ICollection argsCollection)
200                 {
201                         object instance = null;
202                         object[] arguments = null;
203                         Type[] types = new Type[0];
204
205                         if (argsCollection != null) {
206                                 arguments = new object[argsCollection.Count];
207                                 types = new Type[argsCollection.Count];
208                                 argsCollection.CopyTo (arguments, 0);
209
210                                 for (int i=0; i < arguments.Length; i++) {
211                                         if (arguments[i] == null)
212                                                 types[i] = null;
213                                         else
214                                                 types[i] = arguments[i].GetType ();
215                                 }
216                         }
217
218                         ConstructorInfo ctor = type.GetConstructor (types);
219                         if (ctor != null) {
220                                 instance = ctor.Invoke (arguments);
221                         }
222
223                         return instance;
224                 }
225
226                 public object GetSerializer (Type componentType, Type serializerType)
227                 {
228                         VerifyInSession ();
229                         
230                         if (serializerType == null)
231                                 throw new ArgumentNullException ("serializerType");
232                                 
233                         object serializer = null;
234
235                         if (componentType != null) {
236                                 // try 1: from cache
237                                 //
238                                 _serializersCache.TryGetValue (componentType, out serializer);
239
240                                 // check for provider attribute and add it to the list of providers
241                                 //
242                                 if (serializer != null && !serializerType.IsAssignableFrom (serializer.GetType ()))
243                                         serializer = null;
244                                 
245                                 AttributeCollection attributes = TypeDescriptor.GetAttributes (componentType);
246                                 DefaultSerializationProviderAttribute providerAttribute = attributes[typeof (DefaultSerializationProviderAttribute)] 
247                                                                                                                                                            as DefaultSerializationProviderAttribute;
248                                 if (providerAttribute != null && this.GetType (providerAttribute.ProviderTypeName) == serializerType) {
249                                         
250                                         object provider = Activator.CreateInstance (this.GetType (providerAttribute.ProviderTypeName), 
251                                                                                                                                  BindingFlags.CreateInstance | BindingFlags.Public | BindingFlags.NonPublic, 
252                                                                                                                                  null, null, null);
253         
254                                         ((IDesignerSerializationManager)this).AddSerializationProvider ((IDesignerSerializationProvider) provider);
255                                 }
256                         }
257                         
258                         // try 2: from provider
259                         //
260                         if (serializer == null) {
261                                 foreach (IDesignerSerializationProvider provider in _serializationProviders) {
262                                         serializer = provider.GetSerializer (this, null, componentType, serializerType);
263                                         if (serializer != null)
264                                                 break;
265                                 }
266                         }
267
268                         if (componentType != null) {
269                                 // try 3: Activator
270                                 //
271                                 if (serializer == null) {
272                                         AttributeCollection attributes = TypeDescriptor.GetAttributes (componentType);
273                                         DesignerSerializerAttribute serializerAttribute = attributes[typeof (DesignerSerializerAttribute)] as DesignerSerializerAttribute;
274                                         if (serializerAttribute != null && this.GetType (serializerAttribute.SerializerTypeName) == serializerType) {
275                                                         serializer = Activator.CreateInstance (this.GetType (serializerAttribute.SerializerTypeName), 
276                                                                                  BindingFlags.CreateInstance | BindingFlags.Public | BindingFlags.NonPublic, 
277                                                                                  null, null, null);
278                                         }
279                                 }
280                                 
281                                 if (serializer != null)
282                                         _serializersCache[componentType] = serializer;
283                         }
284                         
285                         return serializer;
286                 }
287                 
288                 private void VerifyInSession ()
289                 {
290                         if (_session == null)
291                                 throw new InvalidOperationException ("Not in session.");
292                 }
293                 
294                 private void VerifyNotInSession ()
295                 {
296                         if (_session != null)
297                                 throw new InvalidOperationException ("In session.");
298                 }
299                 
300                 public IDisposable CreateSession ()
301                 {
302                         _errors = new ArrayList ();
303                         _session = new Session (this);
304                         _serializersCache = new Dictionary<System.Type,object> ();
305                         _instancesByNameCache = new Dictionary<string,object> ();
306                         _instancesByValueCache = new Dictionary<object, string> ();
307                         _contextStack = new ContextStack ();
308                         
309                         this.OnSessionCreated (EventArgs.Empty);
310
311                         return _session;
312                 }
313                 
314                 protected virtual void OnSessionDisposed (EventArgs e)
315                 {
316                         _errors.Clear ();
317                         _errors = null;
318                         _serializersCache.Clear ();
319                         _serializersCache = null;
320                         _instancesByNameCache.Clear ();
321                         _instancesByNameCache = null;
322                         _instancesByValueCache.Clear ();
323                         _instancesByValueCache = null;
324                         _session = null;
325                         _contextStack = null;
326                         _resolveNameHandler = null;
327                         _serializationCompleteHandler = null;
328                         
329                         if (SessionDisposed != null) {
330                                 SessionDisposed (this, e);
331                         }
332
333                         if (_serializationCompleteHandler != null)
334                                 _serializationCompleteHandler (this, EventArgs.Empty);
335                 }
336                                 
337                 protected virtual Type GetType (string name)
338                 {
339                         if (name == null)
340                                 throw new ArgumentNullException ("name");
341                         
342                         this.VerifyInSession ();
343                         
344                         Type result = null;
345                         ITypeResolutionService typeResSvc = this.GetService (typeof (ITypeResolutionService)) as ITypeResolutionService;
346                         if (typeResSvc != null)
347                                 result = typeResSvc.GetType (name);
348                         if (result == null)
349                                 result = Type.GetType (name);
350                         
351                         return result;
352                 }
353                                                                                 
354 #region IDesignerSerializationManager implementation
355                 
356                 protected virtual void OnResolveName (ResolveNameEventArgs e)
357                 {
358                         if (_resolveNameHandler != null) {
359                                 _resolveNameHandler (this, e);
360                         }
361                 }       
362                 
363                 void IDesignerSerializationManager.AddSerializationProvider (IDesignerSerializationProvider provider)
364                 {
365                         if (_serializationProviders == null)
366                                 _serializationProviders = new List <IDesignerSerializationProvider> ();
367                         
368                         if (!_serializationProviders.Contains (provider))
369                                 _serializationProviders.Add (provider);
370                 }
371                 
372                 void IDesignerSerializationManager.RemoveSerializationProvider (IDesignerSerializationProvider provider)
373                 {
374                         if (_serializationProviders != null)
375                                 _serializationProviders.Remove (provider);
376                 }
377                 
378                 object IDesignerSerializationManager.CreateInstance (Type type, ICollection arguments, string name, bool addToContainer)
379                 {
380                         return this.CreateInstance (type, arguments, name, addToContainer);
381                 }
382                 
383                 object IDesignerSerializationManager.GetInstance (string name)
384                 {
385                         if (name == null)
386                                 throw new ArgumentNullException ("name");
387                         this.VerifyInSession ();
388                         
389                         object instance = null;
390                         _instancesByNameCache.TryGetValue (name, out instance);
391                         
392                         if (instance == null && _preserveNames && this.Container != null)
393                                 instance = this.Container.Components[name];
394                         
395                         if (instance == null)
396                                 instance = this.RequestInstance (name);
397                         
398                         return instance;
399                 }
400                 
401                 private object RequestInstance (string name)
402                 {
403                         ResolveNameEventArgs args = new ResolveNameEventArgs (name);
404                         this.OnResolveName (args);
405                         return args.Value;
406                 }
407                 
408                 Type IDesignerSerializationManager.GetType (string name)
409                 {
410                         return this.GetType (name);
411                 }
412                 
413                 object IDesignerSerializationManager.GetSerializer (Type type, Type serializerType)
414                 {
415                         return this.GetSerializer (type, serializerType);
416                 }
417                 
418                 string IDesignerSerializationManager.GetName (object instance)
419                 {
420                         if (instance == null)
421                                 throw new ArgumentNullException ("instance");
422                         this.VerifyInSession ();
423                         
424                         string name = null;
425                         if (instance is IComponent) {
426                                 ISite site = ((IComponent)instance).Site;
427                                 if (site != null && site is INestedSite)
428                                         name = ((INestedSite)site).FullName;
429                                 else if (site != null)
430                                         name = site.Name;
431                         }
432                         if (name == null)
433                                 _instancesByValueCache.TryGetValue (instance, out name);
434                         return name;
435                 }
436                 
437                 void IDesignerSerializationManager.SetName (object instance, string name)
438                 {
439                         if (instance == null)
440                                 throw new ArgumentNullException ("instance");
441                         if (name == null)
442                                 throw new ArgumentNullException ("name");
443                         
444                         if (_instancesByNameCache.ContainsKey (name))
445                                 throw new ArgumentException ("The object specified by instance already has a name, or name is already used by another named object.");
446                         
447                         _instancesByNameCache.Add (name, instance);
448                         _instancesByValueCache.Add (instance, name);
449                 }
450                 
451                 void IDesignerSerializationManager.ReportError (object error)
452                 {
453                    this.VerifyInSession ();
454                    _errors.Add (error);
455                 }
456                 
457                 ContextStack IDesignerSerializationManager.Context {
458                         get { return _contextStack; }
459                 }
460                 
461                 PropertyDescriptorCollection IDesignerSerializationManager.Properties {
462                         get {
463                                 PropertyDescriptorCollection properties = new PropertyDescriptorCollection (new PropertyDescriptor[0]);
464                                 object component = this.PropertyProvider;
465                                 if (component != null)
466                                    properties = TypeDescriptor.GetProperties (component);
467                                 
468                                 return properties;
469                         }
470                 }
471                 
472                 private EventHandler _serializationCompleteHandler;
473                 private ResolveNameEventHandler _resolveNameHandler;
474                 
475                 event EventHandler IDesignerSerializationManager.SerializationComplete {
476                         add {
477                                 this.VerifyInSession ();
478                                 _serializationCompleteHandler = (EventHandler) Delegate.Combine (_serializationCompleteHandler, value);
479                         }
480                         remove {
481                                 _serializationCompleteHandler = (EventHandler) Delegate.Remove (_serializationCompleteHandler, value);
482                         }
483                 }
484                                 
485                 event ResolveNameEventHandler IDesignerSerializationManager.ResolveName {
486                         add {
487                                 this.VerifyInSession ();
488                                 _resolveNameHandler = (ResolveNameEventHandler) Delegate.Combine (_resolveNameHandler, value);
489                         }
490                         remove {
491                                 _resolveNameHandler = (ResolveNameEventHandler) Delegate.Remove (_resolveNameHandler, value);
492                         }
493                 }         
494 #endregion
495                 
496                 object IServiceProvider.GetService (Type service)
497                 {
498                         return this.GetService (service);
499                 }
500                 
501                 protected virtual object GetService (Type service)
502                 {
503                         object result = null;
504                         if (_serviceProvider != null)
505                                 result = _serviceProvider.GetService (service);
506                         
507                         return result;
508                 }
509         }
510 }
511 #endif