2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.Design / System.ComponentModel.Design.Serialization / DesignerSerializationManager.cs
blobf1c8127cb86474a547d8c0b2ffbeb8e6cf728f7f
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
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.
30 #if NET_2_0
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;
41 namespace System.ComponentModel.Design.Serialization
44 public class DesignerSerializationManager : IDesignerSerializationManager, IServiceProvider
47 private class Session : IDisposable
50 private DesignerSerializationManager _manager;
52 public Session (DesignerSerializationManager manager)
54 _manager = manager;
57 public void Dispose ()
59 _manager.OnSessionDisposed (EventArgs.Empty);
65 public DesignerSerializationManager () : this (null)
69 // This constructor sets the PreserveNames and ValidateRecycledTypes properties to true.
71 public DesignerSerializationManager (IServiceProvider provider)
73 _serviceProvider = provider;
74 _preserveNames = true;
75 _validateRecycledTypes = true;
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;
93 public bool RecycleInstances {
94 get { return _recycleInstances; }
95 set {
96 VerifyNotInSession ();
97 _recycleInstances = value;
101 public bool PreserveNames {
102 get { return _preserveNames; }
103 set {
104 VerifyNotInSession ();
105 _preserveNames = value;
109 public bool ValidateRecycledTypes {
110 get { return _validateRecycledTypes; }
111 set {
112 VerifyNotInSession ();
113 _validateRecycledTypes = value;
117 public IContainer Container {
118 get {
119 if (_designerContainer == null) {
120 _designerContainer = (this.GetService (typeof (IDesignerHost)) as IDesignerHost).Container;
122 return _designerContainer;
124 set{
125 VerifyNotInSession ();
126 _designerContainer = value;
130 public object PropertyProvider {
131 get { return _propertyProvider; }
132 set { _propertyProvider = value; }
135 public IList Errors {
136 get { return _errors; }
139 public event EventHandler SessionDisposed;
140 public event EventHandler SessionCreated;
142 protected virtual void OnSessionCreated (EventArgs e)
144 if (SessionCreated != null) {
145 SessionCreated (this, e);
149 // For behaviour description:
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
154 protected virtual object CreateInstance (Type type, ICollection arguments, string name, bool addToContainer)
156 VerifyInSession ();
157 object instance = null;
159 if (name != null && _recycleInstances) {
160 _instancesByNameCache.TryGetValue (name, out instance);
161 if (instance != null && _validateRecycledTypes) {
162 if (instance.GetType () != type)
163 instance = null;
167 if (instance == null || !_recycleInstances)
168 instance = this.CreateInstance (type, arguments);
170 if (addToContainer && instance != null && this.Container != null && typeof (IComponent).IsAssignableFrom (type)) {
171 if (_preserveNames) {
172 this.Container.Add ((IComponent) instance, name);
174 else {
175 if (name != null && this.Container.Components[name] != null) {
176 this.Container.Add ((IComponent) instance);
178 else {
179 this.Container.Add ((IComponent) instance, name);
182 ISite site = ((IComponent)instance).Site; // get the name from the site in case a name has been generated.
183 if (site != null)
184 name = site.Name;
187 if (instance != null && name != null) {
188 _instancesByNameCache[name] = instance;
189 _instancesByValueCache[instance] = name;
192 return instance;
195 // Invokes the constructor that matches the arguments
197 private object CreateInstance (Type type, ICollection argsCollection)
199 object instance = null;
200 object[] arguments = null;
201 Type[] types = new Type[0];
203 if (argsCollection != null) {
204 arguments = new object[argsCollection.Count];
205 types = new Type[argsCollection.Count];
206 argsCollection.CopyTo (arguments, 0);
208 for (int i=0; i < arguments.Length; i++) {
209 if (arguments[i] == null)
210 types[i] = null;
211 else
212 types[i] = arguments[i].GetType ();
216 ConstructorInfo ctor = type.GetConstructor (types);
217 if (ctor != null) {
218 instance = ctor.Invoke (arguments);
221 return instance;
224 public object GetSerializer (Type componentType, Type serializerType)
226 VerifyInSession ();
228 if (serializerType == null)
229 throw new ArgumentNullException ("serializerType");
231 object serializer = null;
233 if (componentType != null) {
234 // try 1: from cache
236 _serializersCache.TryGetValue (componentType, out serializer);
238 // check for provider attribute and add it to the list of providers
240 if (serializer != null && !serializerType.IsAssignableFrom (serializer.GetType ()))
241 serializer = null;
243 AttributeCollection attributes = TypeDescriptor.GetAttributes (componentType);
244 DefaultSerializationProviderAttribute providerAttribute = attributes[typeof (DefaultSerializationProviderAttribute)]
245 as DefaultSerializationProviderAttribute;
246 if (providerAttribute != null && this.GetType (providerAttribute.ProviderTypeName) == serializerType) {
247 object provider = Activator.CreateInstance (this.GetType (providerAttribute.ProviderTypeName),
248 BindingFlags.CreateInstance | BindingFlags.Public | BindingFlags.NonPublic,
249 null, null, null);
250 ((IDesignerSerializationManager)this).AddSerializationProvider ((IDesignerSerializationProvider) provider);
254 // try 2: DesignerSerializerAttribute
256 if (serializer == null && componentType != null) {
257 AttributeCollection attributes = TypeDescriptor.GetAttributes (componentType);
258 DesignerSerializerAttribute serializerAttribute = attributes[typeof (DesignerSerializerAttribute)] as DesignerSerializerAttribute;
259 if (serializerAttribute != null &&
260 this.GetType (serializerAttribute.SerializerBaseTypeName) == serializerType) {
261 try {
262 serializer = Activator.CreateInstance (this.GetType (serializerAttribute.SerializerTypeName),
263 BindingFlags.CreateInstance | BindingFlags.Instance |
264 BindingFlags.Public | BindingFlags.NonPublic,
265 null, null, null);
266 } catch {}
269 if (serializer != null)
270 _serializersCache[componentType] = serializer;
273 // try 3: from provider
275 if (serializer == null && _serializationProviders != null) {
276 foreach (IDesignerSerializationProvider provider in _serializationProviders) {
277 serializer = provider.GetSerializer (this, null, componentType, serializerType);
278 if (serializer != null)
279 break;
283 return serializer;
286 private void VerifyInSession ()
288 if (_session == null)
289 throw new InvalidOperationException ("Not in session.");
292 private void VerifyNotInSession ()
294 if (_session != null)
295 throw new InvalidOperationException ("In session.");
298 public IDisposable CreateSession ()
300 VerifyNotInSession ();
301 _errors = new ArrayList ();
302 _session = new Session (this);
303 _serializersCache = new Dictionary<System.Type,object> ();
304 _instancesByNameCache = new Dictionary<string,object> ();
305 _instancesByValueCache = new Dictionary<object, string> ();
306 _contextStack = new ContextStack ();
308 this.OnSessionCreated (EventArgs.Empty);
310 return _session;
313 protected virtual void OnSessionDisposed (EventArgs e)
315 _errors.Clear ();
316 _errors = null;
317 _serializersCache.Clear ();
318 _serializersCache = null;
319 _instancesByNameCache.Clear ();
320 _instancesByNameCache = null;
321 _instancesByValueCache.Clear ();
322 _instancesByValueCache = null;
323 _session = null;
324 _contextStack = null;
325 _resolveNameHandler = null;
326 _serializationCompleteHandler = null;
328 if (SessionDisposed != null) {
329 SessionDisposed (this, e);
332 if (_serializationCompleteHandler != null)
333 _serializationCompleteHandler (this, EventArgs.Empty);
336 protected virtual Type GetType (string name)
338 if (name == null)
339 throw new ArgumentNullException ("name");
341 this.VerifyInSession ();
343 Type result = null;
344 ITypeResolutionService typeResSvc = this.GetService (typeof (ITypeResolutionService)) as ITypeResolutionService;
345 if (typeResSvc != null)
346 result = typeResSvc.GetType (name);
347 if (result == null)
348 result = Type.GetType (name);
350 return result;
353 #region IDesignerSerializationManager implementation
355 protected virtual void OnResolveName (ResolveNameEventArgs e)
357 if (_resolveNameHandler != null) {
358 _resolveNameHandler (this, e);
362 void IDesignerSerializationManager.AddSerializationProvider (IDesignerSerializationProvider provider)
364 if (_serializationProviders == null)
365 _serializationProviders = new List <IDesignerSerializationProvider> ();
367 if (!_serializationProviders.Contains (provider))
368 _serializationProviders.Add (provider);
371 void IDesignerSerializationManager.RemoveSerializationProvider (IDesignerSerializationProvider provider)
373 if (_serializationProviders != null)
374 _serializationProviders.Remove (provider);
377 object IDesignerSerializationManager.CreateInstance (Type type, ICollection arguments, string name, bool addToContainer)
379 return this.CreateInstance (type, arguments, name, addToContainer);
382 object IDesignerSerializationManager.GetInstance (string name)
384 if (name == null)
385 throw new ArgumentNullException ("name");
386 this.VerifyInSession ();
388 object instance = null;
389 _instancesByNameCache.TryGetValue (name, out instance);
391 if (instance == null && this.Container != null)
392 instance = this.Container.Components[name];
394 if (instance == null)
395 instance = this.RequestInstance (name);
397 return instance;
400 private object RequestInstance (string name)
402 ResolveNameEventArgs args = new ResolveNameEventArgs (name);
403 this.OnResolveName (args);
404 return args.Value;
407 Type IDesignerSerializationManager.GetType (string name)
409 return this.GetType (name);
412 object IDesignerSerializationManager.GetSerializer (Type type, Type serializerType)
414 return this.GetSerializer (type, serializerType);
417 string IDesignerSerializationManager.GetName (object instance)
419 if (instance == null)
420 throw new ArgumentNullException ("instance");
421 this.VerifyInSession ();
423 string name = null;
424 if (instance is IComponent) {
425 ISite site = ((IComponent)instance).Site;
426 if (site != null && site is INestedSite)
427 name = ((INestedSite)site).FullName;
428 else if (site != null)
429 name = site.Name;
431 if (name == null)
432 _instancesByValueCache.TryGetValue (instance, out name);
433 return name;
436 void IDesignerSerializationManager.SetName (object instance, string name)
438 if (instance == null)
439 throw new ArgumentNullException ("instance");
440 if (name == null)
441 throw new ArgumentNullException ("name");
443 if (_instancesByNameCache.ContainsKey (name))
444 throw new ArgumentException ("The object specified by instance already has a name, or name is already used by another named object.");
446 _instancesByNameCache.Add (name, instance);
447 _instancesByValueCache.Add (instance, name);
450 void IDesignerSerializationManager.ReportError (object error)
452 this.VerifyInSession ();
453 _errors.Add (error);
456 ContextStack IDesignerSerializationManager.Context {
457 get { return _contextStack; }
460 PropertyDescriptorCollection IDesignerSerializationManager.Properties {
461 get {
462 PropertyDescriptorCollection properties = new PropertyDescriptorCollection (new PropertyDescriptor[0]);
463 object component = this.PropertyProvider;
464 if (component != null)
465 properties = TypeDescriptor.GetProperties (component);
467 return properties;
471 private EventHandler _serializationCompleteHandler;
472 private ResolveNameEventHandler _resolveNameHandler;
474 event EventHandler IDesignerSerializationManager.SerializationComplete {
475 add {
476 this.VerifyInSession ();
477 _serializationCompleteHandler = (EventHandler) Delegate.Combine (_serializationCompleteHandler, value);
479 remove {
480 _serializationCompleteHandler = (EventHandler) Delegate.Remove (_serializationCompleteHandler, value);
484 event ResolveNameEventHandler IDesignerSerializationManager.ResolveName {
485 add {
486 this.VerifyInSession ();
487 _resolveNameHandler = (ResolveNameEventHandler) Delegate.Combine (_resolveNameHandler, value);
489 remove {
490 _resolveNameHandler = (ResolveNameEventHandler) Delegate.Remove (_resolveNameHandler, value);
493 #endregion
495 object IServiceProvider.GetService (Type service)
497 return this.GetService (service);
500 protected virtual object GetService (Type service)
502 object result = null;
503 if (_serviceProvider != null)
504 result = _serviceProvider.GetService (service);
506 return result;
510 #endif