2 // System.ComponentModel.Design.Serialization.CodeDomDesignerLoader
5 // Ivan N. Zlatev (contact i-nZ.net)
7 // (C) 2007 Ivan N. Zlatev
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
33 using System.Collections;
34 using System.ComponentModel;
35 using System.ComponentModel.Design;
38 using System.CodeDom.Compiler;
40 namespace System.ComponentModel.Design.Serialization
42 public abstract class CodeDomDesignerLoader : BasicDesignerLoader, INameCreationService, IDesignerSerializationService
44 private CodeDomSerializer _rootSerializer;
46 protected CodeDomDesignerLoader ()
50 protected override void Initialize ()
53 base.LoaderHost.AddService (typeof (IDesignerSerializationService), this);
54 base.LoaderHost.AddService (typeof (INameCreationService), this);
55 base.LoaderHost.AddService (typeof (ComponentSerializationService), new
56 CodeDomComponentSerializationService (base.LoaderHost));
57 IDesignerSerializationManager manager = base.LoaderHost.GetService (typeof (IDesignerSerializationManager)) as IDesignerSerializationManager;
59 manager.AddSerializationProvider (CodeDomSerializationProvider.Instance);
62 protected override bool IsReloadNeeded ()
64 if (this.CodeDomProvider is ICodeDomDesignerReload)
65 return ((ICodeDomDesignerReload) CodeDomProvider).ShouldReloadDesigner (Parse ());
66 return base.IsReloadNeeded ();
69 protected override void PerformLoad (IDesignerSerializationManager manager)
72 throw new ArgumentNullException ("manager");
74 CodeCompileUnit document = this.Parse ();
76 throw new NotSupportedException ("The language did not provide a code parser for this file");
78 string namespaceName = null;
79 CodeTypeDeclaration rootDocument = GetFirstCodeTypeDecl (document, out namespaceName);
80 if (rootDocument == null)
81 throw new InvalidOperationException ("Cannot find a declaration in a namespace to load.");
83 _rootSerializer = manager.GetSerializer (manager.GetType (rootDocument.BaseTypes[0].BaseType),
84 typeof (RootCodeDomSerializer)) as CodeDomSerializer;
85 if (_rootSerializer == null)
86 throw new InvalidOperationException ("Serialization not supported for this class");
88 _rootSerializer.Deserialize (manager, rootDocument);
90 base.SetBaseComponentClassName (namespaceName + "." + rootDocument.Name);
93 private CodeTypeDeclaration GetFirstCodeTypeDecl (CodeCompileUnit document, out string namespaceName)
97 foreach (CodeNamespace namesp in document.Namespaces) {
98 foreach (CodeTypeDeclaration declaration in namesp.Types) {
99 if (declaration.IsClass) {
100 namespaceName = namesp.Name;
108 protected override void PerformFlush (IDesignerSerializationManager manager)
110 if (_rootSerializer != null) {
111 CodeTypeDeclaration typeDecl = (CodeTypeDeclaration) _rootSerializer.Serialize (manager,
112 base.LoaderHost.RootComponent);
113 this.Write (MergeTypeDeclWithCompileUnit (typeDecl, this.Parse ()));
117 // Will either add the class or replace an existing class
118 // with the one from GenerateClass ()
120 private CodeCompileUnit MergeTypeDeclWithCompileUnit (CodeTypeDeclaration typeDecl, CodeCompileUnit unit)
122 CodeNamespace namespac = null;
125 foreach (CodeNamespace namesp in unit.Namespaces) {
126 for (int i=0; i< namesp.Types.Count; i++) {
127 if (namesp.Types[i].IsClass) {
135 namespac.Types.RemoveAt (typeIndex);
137 namespac.Types.Add (typeDecl);
142 protected override void OnBeginLoad ()
146 IComponentChangeService service = base.GetService (typeof (IComponentChangeService)) as IComponentChangeService;
148 service.ComponentRename += this.OnComponentRename_EventHandler;
151 protected override void OnBeginUnload ()
153 base.OnBeginUnload ();
155 IComponentChangeService service = base.GetService (typeof (IComponentChangeService)) as IComponentChangeService;
157 service.ComponentRename -= this.OnComponentRename_EventHandler;
160 protected override void OnEndLoad (bool successful, ICollection errors)
162 base.OnEndLoad (successful, errors);
163 // XXX: msdn says overriden
166 private void OnComponentRename_EventHandler (object sender, ComponentRenameEventArgs args)
168 this.OnComponentRename (args.Component, args.OldName, args.NewName);
171 // MSDN says that here one should raise ComponentRename event and that's nonsense.
173 protected virtual void OnComponentRename (object component, string oldName, string newName)
175 // What shall we do with the drunken sailor,
176 // what shall we do with the drunken sailor early in the morning?
179 protected abstract CodeDomProvider CodeDomProvider { get; }
180 protected abstract ITypeResolutionService TypeResolutionService { get; }
181 protected abstract CodeCompileUnit Parse ();
182 protected abstract void Write (CodeCompileUnit unit);
184 public override void Dispose ()
189 #region INameCreationService implementation
191 // very simplistic implementation to generate names like "button1", "someControl2", etc
193 string INameCreationService.CreateName (IContainer container, Type dataType)
195 if (dataType == null)
196 throw new ArgumentNullException ("dataType");
198 string name = dataType.Name;
199 char lower = Char.ToLower (name[0]);
200 name = name.Remove (0, 1);
201 name = name.Insert (0, Char.ToString (lower));
207 if (container != null && container.Components[name + uniqueId] != null) {
211 name = name + uniqueId;
215 if (this.CodeDomProvider != null)
216 name = CodeDomProvider.CreateValidIdentifier (name);
221 bool INameCreationService.IsValidName (string name)
224 throw new ArgumentNullException ("name");
227 if (base.LoaderHost != null && base.LoaderHost.Container.Components[name] != null) {
230 if (this.CodeDomProvider != null) {
231 valid = CodeDomProvider.IsValidIdentifier (name);
233 if (name.Trim().Length == 0)
235 foreach (char c in name) {
236 if (!Char.IsLetterOrDigit (c)) {
247 void INameCreationService.ValidateName (string name)
249 if (!((INameCreationService) this).IsValidName (name))
250 throw new ArgumentException ("Invalid name '" + name + "'");
255 #region IDesignerSerializationService implementation
257 ICollection IDesignerSerializationService.Deserialize (object serializationData)
259 if (serializationData == null)
260 throw new ArgumentNullException ("serializationData");
262 ComponentSerializationService service = LoaderHost.GetService (typeof (ComponentSerializationService)) as ComponentSerializationService;
263 SerializationStore store = serializationData as SerializationStore;
264 if (service != null && serializationData != null)
265 return service.Deserialize (store, this.LoaderHost.Container);
266 return new object[0];
269 object IDesignerSerializationService.Serialize (ICollection objects)
272 throw new ArgumentNullException ("objects");
274 ComponentSerializationService service = LoaderHost.GetService (typeof (ComponentSerializationService)) as ComponentSerializationService;
275 if (service != null) {
276 SerializationStore store = service.CreateStore ();
277 foreach (object o in objects)
278 service.Serialize (store, o);