// // System.ComponentModel.Design.Serialization.CodeDomDesignerLoader // // Authors: // Ivan N. Zlatev (contact i-nZ.net) // // (C) 2007 Ivan N. Zlatev // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections; using System.ComponentModel; using System.ComponentModel.Design; using System.CodeDom; using System.CodeDom.Compiler; namespace System.ComponentModel.Design.Serialization { public abstract class CodeDomDesignerLoader : BasicDesignerLoader, INameCreationService, IDesignerSerializationService { private CodeDomSerializer _rootSerializer; protected CodeDomDesignerLoader () { } protected override void Initialize () { base.Initialize (); base.LoaderHost.AddService (typeof (IDesignerSerializationService), this); base.LoaderHost.AddService (typeof (INameCreationService), this); base.LoaderHost.AddService (typeof (ComponentSerializationService), new CodeDomComponentSerializationService (base.LoaderHost)); if (this.TypeResolutionService != null && LoaderHost.GetService (typeof (ITypeResolutionService)) == null) LoaderHost.AddService (typeof (ITypeResolutionService), this.TypeResolutionService); IDesignerSerializationManager manager = base.LoaderHost.GetService (typeof (IDesignerSerializationManager)) as IDesignerSerializationManager; if (manager != null) manager.AddSerializationProvider (CodeDomSerializationProvider.Instance); } protected override bool IsReloadNeeded () { if (this.CodeDomProvider is ICodeDomDesignerReload) return ((ICodeDomDesignerReload) CodeDomProvider).ShouldReloadDesigner (Parse ()); return base.IsReloadNeeded (); } protected override void PerformLoad (IDesignerSerializationManager manager) { if (manager == null) throw new ArgumentNullException ("manager"); CodeCompileUnit document = this.Parse (); if (document == null) throw new NotSupportedException ("The language did not provide a code parser for this file"); string namespaceName = null; CodeTypeDeclaration rootDocument = GetFirstCodeTypeDecl (document, out namespaceName); if (rootDocument == null) throw new InvalidOperationException ("Cannot find a declaration in a namespace to load."); _rootSerializer = manager.GetSerializer (manager.GetType (rootDocument.BaseTypes[0].BaseType), typeof (RootCodeDomSerializer)) as CodeDomSerializer; if (_rootSerializer == null) throw new InvalidOperationException ("Serialization not supported for this class"); _rootSerializer.Deserialize (manager, rootDocument); base.SetBaseComponentClassName (namespaceName + "." + rootDocument.Name); } private CodeTypeDeclaration GetFirstCodeTypeDecl (CodeCompileUnit document, out string namespaceName) { namespaceName = null; foreach (CodeNamespace namesp in document.Namespaces) { foreach (CodeTypeDeclaration declaration in namesp.Types) { if (declaration.IsClass) { namespaceName = namesp.Name; return declaration; } } } return null; } protected override void PerformFlush (IDesignerSerializationManager manager) { if (_rootSerializer != null) { CodeTypeDeclaration typeDecl = (CodeTypeDeclaration) _rootSerializer.Serialize (manager, base.LoaderHost.RootComponent); this.Write (MergeTypeDeclWithCompileUnit (typeDecl, this.Parse ())); } } // Will either add the class or replace an existing class // with the one from GenerateClass () // private CodeCompileUnit MergeTypeDeclWithCompileUnit (CodeTypeDeclaration typeDecl, CodeCompileUnit unit) { CodeNamespace namespac = null; int typeIndex = -1; foreach (CodeNamespace namesp in unit.Namespaces) { for (int i=0; i< namesp.Types.Count; i++) { if (namesp.Types[i].IsClass) { typeIndex = i; namespac = namesp; } } } if (typeIndex != -1) namespac.Types.RemoveAt (typeIndex); namespac.Types.Add (typeDecl); return unit; } protected override void OnBeginLoad () { base.OnBeginLoad (); IComponentChangeService service = base.GetService (typeof (IComponentChangeService)) as IComponentChangeService; if (service != null) service.ComponentRename += this.OnComponentRename_EventHandler; } protected override void OnBeginUnload () { base.OnBeginUnload (); IComponentChangeService service = base.GetService (typeof (IComponentChangeService)) as IComponentChangeService; if (service != null) service.ComponentRename -= this.OnComponentRename_EventHandler; } protected override void OnEndLoad (bool successful, ICollection errors) { base.OnEndLoad (successful, errors); // XXX: msdn says overriden } private void OnComponentRename_EventHandler (object sender, ComponentRenameEventArgs args) { this.OnComponentRename (args.Component, args.OldName, args.NewName); } // MSDN says that here one should raise ComponentRename event and that's nonsense. // protected virtual void OnComponentRename (object component, string oldName, string newName) { // What shall we do with the drunken sailor, // what shall we do with the drunken sailor early in the morning? } protected abstract CodeDomProvider CodeDomProvider { get; } protected abstract ITypeResolutionService TypeResolutionService { get; } protected abstract CodeCompileUnit Parse (); protected abstract void Write (CodeCompileUnit unit); public override void Dispose () { base.Dispose (); } #region INameCreationService implementation // very simplistic implementation to generate names like "button1", "someControl2", etc // string INameCreationService.CreateName (IContainer container, Type dataType) { if (dataType == null) throw new ArgumentNullException ("dataType"); string name = dataType.Name; char lower = Char.ToLower (name[0]); name = name.Remove (0, 1); name = name.Insert (0, Char.ToString (lower)); int uniqueId = 1; bool unique = false; while (!unique) { if (container != null && container.Components[name + uniqueId] != null) { uniqueId++; } else { unique = true; name = name + uniqueId; } } if (this.CodeDomProvider != null) name = CodeDomProvider.CreateValidIdentifier (name); return name; } bool INameCreationService.IsValidName (string name) { if (name == null) throw new ArgumentNullException ("name"); bool valid = true; if (base.LoaderHost != null && base.LoaderHost.Container.Components[name] != null) { valid = false; } else { if (this.CodeDomProvider != null) { valid = CodeDomProvider.IsValidIdentifier (name); } else { if (name.Trim().Length == 0) valid = false; foreach (char c in name) { if (!Char.IsLetterOrDigit (c)) { valid = false; break; } } } } return valid; } void INameCreationService.ValidateName (string name) { if (!((INameCreationService) this).IsValidName (name)) throw new ArgumentException ("Invalid name '" + name + "'"); } #endregion #region IDesignerSerializationService implementation ICollection IDesignerSerializationService.Deserialize (object serializationData) { if (serializationData == null) throw new ArgumentNullException ("serializationData"); ComponentSerializationService service = LoaderHost.GetService (typeof (ComponentSerializationService)) as ComponentSerializationService; SerializationStore store = serializationData as SerializationStore; if (service != null && serializationData != null) return service.Deserialize (store, this.LoaderHost.Container); return new object[0]; } object IDesignerSerializationService.Serialize (ICollection objects) { if (objects == null) throw new ArgumentNullException ("objects"); ComponentSerializationService service = LoaderHost.GetService (typeof (ComponentSerializationService)) as ComponentSerializationService; if (service != null) { SerializationStore store = service.CreateStore (); foreach (object o in objects) service.Serialize (store, o); store.Close (); return store; } return null; } #endregion } }