small fix
[mono.git] / mcs / class / System.Design / System.ComponentModel.Design.Serialization / CodeDomComponentSerializationService.cs
index 3ffea8d6de463a8c1b256408bd441f65e5e46ff5..f59420e300843cc229f4912a6dd174987f41085f 100644 (file)
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-// STUBS ONLY
-
 #if NET_2_0
 
 using System;
+using System.Runtime.Serialization;
+using System.Runtime.Serialization.Formatters.Binary;
 using System.ComponentModel;
+using System.ComponentModel.Design.Serialization;
 using System.Collections;
+using System.Collections.Generic;
 using System.IO;
 
 namespace System.ComponentModel.Design.Serialization
 {
+       // A ComponentSerializationService that uses a CodeDomSerializationStore 
+       // to serialize Components and MemberDescriptors to CodeStatement and CodeStatementCollection
+       //
        public sealed class CodeDomComponentSerializationService : ComponentSerializationService
        {
+               [Serializable]
+               private class CodeDomSerializationStore : SerializationStore, ISerializable
+               {
+                       [Serializable]
+                       private class Entry
+                       {
+                               private bool _isSerialized;
+                               private object _serialized;
+                               private bool _absolute;
+                               private string _name;
+
+                               protected Entry ()
+                               {
+                               }
+
+                               public Entry (string name)
+                               {
+                                       if (name == null)
+                                               throw new ArgumentNullException ("name");
+                                       _name = name;
+                                       _isSerialized = false;
+                                       _absolute = false;
+                               }
+
+                               public bool IsSerialized {
+                                       get { return _isSerialized; }
+                                       set { _isSerialized = value; }
+                               }
+
+                               public object Serialized {
+                                       get { return _serialized; }
+                                       set { 
+                                               _serialized = value;
+                                               _isSerialized = true;
+                                       }
+                               }
+
+                               public bool Absolute {
+                                       get { return _absolute; }
+                                       set { _absolute = value; }
+                               }
+
+                               public string Name {
+                                       get { return _name; }
+                                       set { _name = value; }
+                               }
+                       }
+
+                       [Serializable]
+                       private class MemberEntry : Entry
+                       {
+                               private MemberDescriptor _descriptor;
+
+                               protected MemberEntry ()
+                               {
+                               }
+
+                               public MemberEntry (MemberDescriptor descriptor)
+                               {
+                                       if (descriptor == null)
+                                               throw new ArgumentNullException ("descriptor");
+                                       _descriptor = descriptor;
+                                       base.Name = descriptor.Name;
+                               }
+
+                               public MemberDescriptor Descriptor {
+                                       get { return _descriptor; }
+                                       set { _descriptor = value; }
+                               }
+                       }
+
+                       [Serializable]
+                       private class ObjectEntry : Entry
+                       {
+                               private Type _type;
+                               [NonSerialized]
+                               private object _instance;
+                               private Dictionary<string,MemberEntry> _members;
+                               private bool _entireObject;
+
+                               protected ObjectEntry ()
+                               {
+                               }
+
+                               public ObjectEntry (object instance, string name) : base (name)
+                               {
+                                       if (instance == null)
+                                               throw new ArgumentNullException ("instance");
+                                       _instance = instance;
+                                       _type = instance.GetType ();
+                                       _entireObject = false;
+                               }
+
+                               public Type Type {
+                                       get { return _type; }
+                               }
+
+                               public object Instance {
+                                       get { return _instance; }
+                                       set { 
+                                               _instance = value;
+                                               if (value != null)
+                                                       _type = value.GetType ();
+                                       }
+                               }
+
+                               public Dictionary<string,MemberEntry> Members {
+                                       get { 
+                                               if (_members == null)
+                                                       _members = new Dictionary <string, MemberEntry> ();
+                                               return _members; 
+                                       }
+                                       set { _members = value; }
+                               }
+
+                               public bool IsEntireObject {
+                                       get { return _entireObject; }
+                                       set { _entireObject = value; }
+                               }
+                       }
+
+                       // When e.g Copy->Pasting a component will not be preserved, but the serialized 
+                       // data will contain references to the original component name. We handle this 
+                       // here by checking whether CreateInstance returns a component with a different
+                       // name and we map the old name to the new one so that GetInstance will return
+                       // a reference to the new component.
+                       //
+                       private class InstanceRedirectorDesignerSerializationManager : IDesignerSerializationManager, IServiceProvider
+                       {
+                               DesignerSerializationManager _manager;
+                               private Dictionary <string, string> _nameMap;
+
+                               public InstanceRedirectorDesignerSerializationManager (IServiceProvider provider, IContainer container,
+                                                                                      bool validateRecycledTypes)
+                               {
+                                       if (provider == null)
+                                               throw new ArgumentNullException ("provider");
+                                       DesignerSerializationManager manager = new DesignerSerializationManager (provider);
+                                       manager.PreserveNames = false;
+                                       if (container != null)
+                                               manager.Container = container;
+                                       manager.ValidateRecycledTypes = validateRecycledTypes;
+                                       _manager = manager;
+                               }
+
+                               public IDisposable CreateSession ()
+                               {
+                                       return _manager.CreateSession ();
+                               }
+
+                               public IList Errors {
+                                       get { return _manager.Errors; }
+                               }
+
+                               object IServiceProvider.GetService (Type service)
+                               {
+                                       return ((IServiceProvider)_manager).GetService (service);
+                               }
+
+                               #region IDesignerSerializationManager Wrapper Implementation
+
+                               void IDesignerSerializationManager.AddSerializationProvider (IDesignerSerializationProvider provider)
+                               {
+                                       ((IDesignerSerializationManager)_manager).AddSerializationProvider (provider);
+                               }
+
+                               void IDesignerSerializationManager.RemoveSerializationProvider (IDesignerSerializationProvider provider)
+                               {
+                                       ((IDesignerSerializationManager)_manager).RemoveSerializationProvider (provider);
+                               }
+
+                               object IDesignerSerializationManager.CreateInstance (Type type, ICollection arguments, string name, bool addToContainer)
+                               {
+                                       object instance = ((IDesignerSerializationManager)_manager).CreateInstance (type, arguments, name, addToContainer);
+                                       string newName = ((IDesignerSerializationManager)_manager).GetName (instance);
+                                       if (newName != name) {
+                                               if (_nameMap == null)
+                                                       _nameMap = new Dictionary<string, string> ();
+                                               _nameMap[name] = newName;
+                                       }
+                                       return instance;
+                               }
+
+                               object IDesignerSerializationManager.GetInstance (string name)
+                               {
+                                       if (_nameMap != null && _nameMap.ContainsKey (name))
+                                               return ((IDesignerSerializationManager)_manager).GetInstance (_nameMap[name]);
+                                       return ((IDesignerSerializationManager)_manager).GetInstance (name);
+                               }
+
+                               Type IDesignerSerializationManager.GetType (string name)
+                               {
+                                       return ((IDesignerSerializationManager)_manager).GetType (name);
+                               }
+
+                               object IDesignerSerializationManager.GetSerializer (Type type, Type serializerType)
+                               {
+                                       return ((IDesignerSerializationManager)_manager).GetSerializer (type, serializerType);
+                               }
+
+                               string IDesignerSerializationManager.GetName (object instance)
+                               {
+                                       return ((IDesignerSerializationManager)_manager).GetName (instance);
+                               }
+
+                               void IDesignerSerializationManager.SetName (object instance, string name)
+                               {
+                                       ((IDesignerSerializationManager)_manager).SetName (instance, name);
+                               }
+
+                               void IDesignerSerializationManager.ReportError (object error)
+                               {
+                                       ((IDesignerSerializationManager)_manager).ReportError (error);
+                               }
+
+                               ContextStack IDesignerSerializationManager.Context {
+                                       get { return ((IDesignerSerializationManager)_manager).Context; }
+                               }
+
+                               PropertyDescriptorCollection IDesignerSerializationManager.Properties {
+                                       get { return ((IDesignerSerializationManager)_manager).Properties; }
+                               }
+
+                               event EventHandler IDesignerSerializationManager.SerializationComplete {
+                                       add { ((IDesignerSerializationManager)_manager).SerializationComplete += value; }
+                                       remove { ((IDesignerSerializationManager)_manager).SerializationComplete -= value; }
+                               }
+
+                               event ResolveNameEventHandler IDesignerSerializationManager.ResolveName {
+                                       add { ((IDesignerSerializationManager)_manager).ResolveName += value; }
+                                       remove { ((IDesignerSerializationManager)_manager).ResolveName -= value; }
+                               }
+                               #endregion
+                       } // InstanceRedirectorDesignerSerializationManager
+
+                       private bool _closed;
+                       private Dictionary <string, ObjectEntry> _objects;
+                       private IServiceProvider _provider;
+                       private ICollection _errors;
+
+                       internal CodeDomSerializationStore () : this (null)
+                       {
+                       }
+
+                       internal CodeDomSerializationStore (IServiceProvider provider)
+                       {
+                               _provider = provider;
+                       }
+
+                       private CodeDomSerializationStore (SerializationInfo info, StreamingContext context)
+                       {
+                               _objects = (Dictionary<string, ObjectEntry>) info.GetValue ("objects", typeof (Dictionary<string, ObjectEntry>));
+                               _closed = (bool) info.GetValue ("closed", typeof (bool));
+                       }
+
+                       void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
+                       {
+                               info.AddValue ("objects", _objects);
+                               info.AddValue ("closed", _closed);
+                       }
+
+                       public override void Close () 
+                       {
+                               if (!_closed) {
+                                       Serialize (_provider);
+                                       _closed = true;
+                               }
+                       }
+
+                       internal static CodeDomSerializationStore Load (Stream stream)
+                       {
+                               return new BinaryFormatter ().Deserialize (stream) as CodeDomSerializationStore;
+                       }
+
+                       public override void Save (Stream stream) 
+                       {
+                               Close ();
+                               new BinaryFormatter ().Serialize (stream, this);
+                       }
+
+                       private void Serialize (IServiceProvider provider)
+                       {
+                               if (provider == null || _objects == null)
+                                       return;
+
+                               // Use a new serialization manager to prevent from "deadlocking" the surface one
+                               // by trying to create new session when one currently exists
+                               // 
+                               InstanceRedirectorDesignerSerializationManager manager = 
+                                       new InstanceRedirectorDesignerSerializationManager (provider, null, false);
+                               ((IDesignerSerializationManager)manager).AddSerializationProvider (CodeDomSerializationProvider.Instance);
+                               IDisposable session = manager.CreateSession ();
+                               foreach (ObjectEntry objectEntry in _objects.Values) {
+                                       if (objectEntry.IsEntireObject) {
+                                               CodeDomSerializer serializer = (CodeDomSerializer) ((IDesignerSerializationManager)manager).GetSerializer (objectEntry.Type, 
+                                                                                                       typeof (CodeDomSerializer));
+                                               if (serializer != null) {
+                                                       object serialized = null;
+                                                       if (objectEntry.Absolute)
+                                                               serialized = serializer.SerializeAbsolute (manager, 
+                                                                                                          objectEntry.Instance);
+                                                       else
+                                                               serialized = serializer.Serialize (manager, objectEntry.Instance);
+                                                       objectEntry.Serialized = serialized;
+                                               }
+                                       } else {
+                                               foreach (MemberEntry memberEntry in objectEntry.Members.Values) {
+                                                       CodeDomSerializer serializer = (CodeDomSerializer) ((IDesignerSerializationManager)manager).GetSerializer (
+                                                               objectEntry.Type, typeof (CodeDomSerializer));
+                                                       if (serializer != null) {
+                                                               object serialized = null;
+                                                               if (memberEntry.Absolute) {
+                                                                       serialized = serializer.SerializeMemberAbsolute (manager, 
+                                                                                                                        objectEntry.Instance, 
+                                                                                                                        memberEntry.Descriptor);
+                                                               } else {
+                                                                       serialized = serializer.SerializeMember (manager,
+                                                                                                                objectEntry.Instance, 
+                                                                                                                memberEntry.Descriptor);
+                                                               }
+                                                               memberEntry.Serialized = serialized;
+                                                       }
+                                               }
+                                       }
+                                       _errors = manager.Errors;
+                               }
+                               _errors = manager.Errors;
+                               session.Dispose ();
+                       }
+
+                       internal void AddObject (object instance, bool absolute)
+                       {
+                               if (_closed)
+                                       throw new InvalidOperationException ("store is closed");
+
+                               if (_objects == null)
+                                       _objects = new Dictionary <string, ObjectEntry> ();
+                               string objectName = GetName (instance);
+
+                               if (!_objects.ContainsKey (objectName)) {
+                                       ObjectEntry objectEntry = new ObjectEntry (instance, objectName);
+                                       objectEntry.Absolute = absolute;
+                                       objectEntry.IsEntireObject = true;
+                                       _objects[objectName] = objectEntry;
+                               }
+                       }
+
+                       internal void AddMember (object owner, MemberDescriptor member, bool absolute)
+                       {
+                               if (_closed)
+                                       throw new InvalidOperationException ("store is closed");
+                               if (member == null)
+                                       throw new ArgumentNullException ("member");
+                               if (owner == null)
+                                       throw new ArgumentNullException ("owner");
+
+                               if (_objects == null)
+                                       _objects = new Dictionary <string, ObjectEntry> ();
+
+                               string objectName = GetName (owner);
+                               if (!_objects.ContainsKey (objectName))
+                                       _objects.Add (objectName,  new ObjectEntry (owner, objectName));
+                               MemberEntry memberEntry = new MemberEntry (member);
+                               memberEntry.Absolute = absolute;
+                               _objects[objectName].Members[member.Name] = memberEntry;
+                       }
+
+                       private string GetName (object value)
+                       {
+                               if (value == null)
+                                       throw new ArgumentNullException ("value");
+                               string name = null;
+
+                               IComponent component = value as IComponent;
+                               if (component != null && component.Site != null) {
+                                       if (component.Site is INestedSite)
+                                               name = ((INestedSite)component.Site).FullName;
+                                       else
+                                               name = component.Site != null ? component.Site.Name : null;
+                               } else if (value is MemberDescriptor) {
+                                       name = ((MemberDescriptor) value).Name;
+                               } else {
+                                       name = value.GetHashCode ().ToString ();
+                               }
+
+                               return name;
+                       }
+
+                       internal ICollection Deserialize (IServiceProvider provider, IContainer container, 
+                                                         bool validateRecycledTypes, bool applyDefaults)
+                       {
+                               List<object> objectInstances = new List<object> ();
+
+                               if (provider == null || _objects == null)
+                                       return objectInstances;
+                               _provider = provider;
+
+                               // Use a new serialization manager to prevent from "deadlocking" the surface one
+                               // by trying to create new session when one currently exists
+                               // 
+                               InstanceRedirectorDesignerSerializationManager manager = 
+                                       new InstanceRedirectorDesignerSerializationManager (provider, container, validateRecycledTypes);
+                               ((IDesignerSerializationManager)manager).AddSerializationProvider (CodeDomSerializationProvider.Instance);
+                               IDisposable session = manager.CreateSession ();
+                               foreach (ObjectEntry entry in _objects.Values)
+                                       objectInstances.Add (DeserializeEntry (manager, entry));
+                               _errors = manager.Errors;
+                               session.Dispose ();
+                               return objectInstances;
+                       }
+
+                       private object DeserializeEntry (IDesignerSerializationManager manager, ObjectEntry objectEntry)
+                       {
+                               object deserialized = null;
+
+                               if (objectEntry.IsEntireObject) {
+                                       CodeDomSerializer serializer = (CodeDomSerializer) manager.GetSerializer (objectEntry.Type, 
+                                                                                                                 typeof (CodeDomSerializer));
+                                       if (serializer != null) {
+                                               deserialized = serializer.Deserialize (manager, objectEntry.Serialized);
+                                               // check if the name of the object has changed
+                                               // (if it e.g clashes with another name)
+                                               string newName = manager.GetName (deserialized);
+                                               if (newName != objectEntry.Name)
+                                                       objectEntry.Name = newName;
+                                       }
+                               } else {
+                                       foreach (MemberEntry memberEntry in objectEntry.Members.Values) {
+                                               CodeDomSerializer serializer = (CodeDomSerializer) manager.GetSerializer (objectEntry.Type, 
+                                                                                                                         typeof (CodeDomSerializer));
+                                               if (serializer != null) 
+                                                       serializer.Deserialize (manager, memberEntry.Serialized);
+                                       }
+                               }
+
+                               return deserialized;
+                       }
+
+                       public override ICollection Errors {
+                               get {
+                                       if (_errors == null)
+                                               _errors = new object[0];
+                                       return _errors;
+                               }
+                       }
+               } // CodeDomSerializationStore
+
+               private IServiceProvider _provider;
 
                public CodeDomComponentSerializationService () : this (null)
                {
@@ -47,51 +500,90 @@ namespace System.ComponentModel.Design.Serialization
 
                public CodeDomComponentSerializationService (IServiceProvider provider)
                {
+                       _provider = provider;
                }
 
                public override SerializationStore CreateStore ()
                {
-                       throw new NotImplementedException ();
+                       return new CodeDomSerializationStore (_provider);
+               }
+
+               public override SerializationStore LoadStore (Stream stream)
+               {
+                       return CodeDomSerializationStore.Load (stream);
                }
 
                public override ICollection Deserialize (SerializationStore store)
                {
-                       throw new NotImplementedException ();
+                       return this.Deserialize (store, null);
                }
 
                public override ICollection Deserialize (SerializationStore store, IContainer container)
                {
-                       throw new NotImplementedException ();
+                       return DeserializeCore (store, container, true, true);
                }
 
-               public override SerializationStore LoadStore (Stream stream)
+               public override void DeserializeTo (SerializationStore store, IContainer container, bool validateRecycledTypes, bool applyDefaults)
                {
-                       throw new NotImplementedException ();
+                       DeserializeCore (store, container, validateRecycledTypes, applyDefaults);
+               }
+
+               private ICollection DeserializeCore (SerializationStore store, IContainer container, bool validateRecycledTypes, 
+                                                    bool applyDefaults)
+               {
+                       CodeDomSerializationStore codeDomStore = store as CodeDomSerializationStore;
+                       if (codeDomStore == null)
+                               throw new InvalidOperationException ("store type unsupported");
+                       return codeDomStore.Deserialize (_provider, container, validateRecycledTypes, applyDefaults);
                }
 
                public override void Serialize (SerializationStore store, object value)
                {
-                       throw new NotImplementedException ();
+                       SerializeCore (store, value, false);
                }
 
                public override void SerializeAbsolute (SerializationStore store, object value)
                {
-                       throw new NotImplementedException ();
+                       SerializeCore (store, value, true);
                }
 
                public override void SerializeMember (SerializationStore store, object owningObject, MemberDescriptor member)
                {
-                       throw new NotImplementedException ();
+                       SerializeMemberCore (store, owningObject, member, false);
                }
 
                public override void SerializeMemberAbsolute (SerializationStore store, object owningObject, MemberDescriptor member)
                {
-                       throw new NotImplementedException ();
+                       SerializeMemberCore (store, owningObject, member, true);
                }
 
-               public override void DeserializeTo (SerializationStore store, IContainer container, bool validateRecycledTypes, bool applyDefaults)
+               private void SerializeCore (SerializationStore store, object value, bool absolute)
+               {
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
+                       if (store == null)
+                               throw new ArgumentNullException ("store");
+
+                       CodeDomSerializationStore codeDomStore = store as CodeDomSerializationStore;
+                       if (store == null)
+                               throw new InvalidOperationException ("store type unsupported");
+
+                       codeDomStore.AddObject (value, absolute);
+               }
+
+               private void SerializeMemberCore (SerializationStore store, object owningObject, MemberDescriptor member, bool absolute)
                {
-                       throw new NotImplementedException ();
+                       if (member == null)
+                               throw new ArgumentNullException ("member");
+                       if (owningObject == null)
+                               throw new ArgumentNullException ("owningObject");
+                       if (store == null)
+                               throw new ArgumentNullException ("store");
+
+                       CodeDomSerializationStore codeDomStore = store as CodeDomSerializationStore;
+                       if (codeDomStore == null)
+                               throw new InvalidOperationException ("store type unsupported");
+                       codeDomStore.AddMember (owningObject, member, absolute);
                }
        }
 }