2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.Design / System.ComponentModel.Design.Serialization / CodeDomDesignerLoader.cs
bloba6ec3e8e7485104cf3090310f153278404124eaf
1 //
2 // System.ComponentModel.Design.Serialization.CodeDomDesignerLoader
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.ComponentModel;
35 using System.ComponentModel.Design;
37 using System.CodeDom;
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 ()
52 base.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 if (this.TypeResolutionService != null &&
58 LoaderHost.GetService (typeof (ITypeResolutionService)) == null)
59 LoaderHost.AddService (typeof (ITypeResolutionService), this.TypeResolutionService);
60 IDesignerSerializationManager manager = base.LoaderHost.GetService (typeof (IDesignerSerializationManager)) as IDesignerSerializationManager;
61 if (manager != null)
62 manager.AddSerializationProvider (CodeDomSerializationProvider.Instance);
65 protected override bool IsReloadNeeded ()
67 if (this.CodeDomProvider is ICodeDomDesignerReload)
68 return ((ICodeDomDesignerReload) CodeDomProvider).ShouldReloadDesigner (Parse ());
69 return base.IsReloadNeeded ();
72 protected override void PerformLoad (IDesignerSerializationManager manager)
74 if (manager == null)
75 throw new ArgumentNullException ("manager");
77 CodeCompileUnit document = this.Parse ();
78 if (document == null)
79 throw new NotSupportedException ("The language did not provide a code parser for this file");
81 string namespaceName = null;
82 CodeTypeDeclaration rootDocument = GetFirstCodeTypeDecl (document, out namespaceName);
83 if (rootDocument == null)
84 throw new InvalidOperationException ("Cannot find a declaration in a namespace to load.");
86 _rootSerializer = manager.GetSerializer (manager.GetType (rootDocument.BaseTypes[0].BaseType),
87 typeof (RootCodeDomSerializer)) as CodeDomSerializer;
88 if (_rootSerializer == null)
89 throw new InvalidOperationException ("Serialization not supported for this class");
91 _rootSerializer.Deserialize (manager, rootDocument);
93 base.SetBaseComponentClassName (namespaceName + "." + rootDocument.Name);
96 private CodeTypeDeclaration GetFirstCodeTypeDecl (CodeCompileUnit document, out string namespaceName)
98 namespaceName = null;
100 foreach (CodeNamespace namesp in document.Namespaces) {
101 foreach (CodeTypeDeclaration declaration in namesp.Types) {
102 if (declaration.IsClass) {
103 namespaceName = namesp.Name;
104 return declaration;
108 return null;
111 protected override void PerformFlush (IDesignerSerializationManager manager)
113 if (_rootSerializer != null) {
114 CodeTypeDeclaration typeDecl = (CodeTypeDeclaration) _rootSerializer.Serialize (manager,
115 base.LoaderHost.RootComponent);
116 this.Write (MergeTypeDeclWithCompileUnit (typeDecl, this.Parse ()));
120 // Will either add the class or replace an existing class
121 // with the one from GenerateClass ()
123 private CodeCompileUnit MergeTypeDeclWithCompileUnit (CodeTypeDeclaration typeDecl, CodeCompileUnit unit)
125 CodeNamespace namespac = null;
126 int typeIndex = -1;
128 foreach (CodeNamespace namesp in unit.Namespaces) {
129 for (int i=0; i< namesp.Types.Count; i++) {
130 if (namesp.Types[i].IsClass) {
131 typeIndex = i;
132 namespac = namesp;
137 if (typeIndex != -1)
138 namespac.Types.RemoveAt (typeIndex);
140 namespac.Types.Add (typeDecl);
142 return unit;
145 protected override void OnBeginLoad ()
147 base.OnBeginLoad ();
149 IComponentChangeService service = base.GetService (typeof (IComponentChangeService)) as IComponentChangeService;
150 if (service != null)
151 service.ComponentRename += this.OnComponentRename_EventHandler;
154 protected override void OnBeginUnload ()
156 base.OnBeginUnload ();
158 IComponentChangeService service = base.GetService (typeof (IComponentChangeService)) as IComponentChangeService;
159 if (service != null)
160 service.ComponentRename -= this.OnComponentRename_EventHandler;
163 protected override void OnEndLoad (bool successful, ICollection errors)
165 base.OnEndLoad (successful, errors);
166 // XXX: msdn says overriden
169 private void OnComponentRename_EventHandler (object sender, ComponentRenameEventArgs args)
171 this.OnComponentRename (args.Component, args.OldName, args.NewName);
174 // MSDN says that here one should raise ComponentRename event and that's nonsense.
176 protected virtual void OnComponentRename (object component, string oldName, string newName)
178 // What shall we do with the drunken sailor,
179 // what shall we do with the drunken sailor early in the morning?
182 protected abstract CodeDomProvider CodeDomProvider { get; }
183 protected abstract ITypeResolutionService TypeResolutionService { get; }
184 protected abstract CodeCompileUnit Parse ();
185 protected abstract void Write (CodeCompileUnit unit);
187 public override void Dispose ()
189 base.Dispose ();
192 #region INameCreationService implementation
194 // very simplistic implementation to generate names like "button1", "someControl2", etc
196 string INameCreationService.CreateName (IContainer container, Type dataType)
198 if (dataType == null)
199 throw new ArgumentNullException ("dataType");
201 string name = dataType.Name;
202 char lower = Char.ToLower (name[0]);
203 name = name.Remove (0, 1);
204 name = name.Insert (0, Char.ToString (lower));
206 int uniqueId = 1;
207 bool unique = false;
209 while (!unique) {
210 if (container != null && container.Components[name + uniqueId] != null) {
211 uniqueId++;
212 } else {
213 unique = true;
214 name = name + uniqueId;
218 if (this.CodeDomProvider != null)
219 name = CodeDomProvider.CreateValidIdentifier (name);
221 return name;
224 bool INameCreationService.IsValidName (string name)
226 if (name == null)
227 throw new ArgumentNullException ("name");
229 bool valid = true;
230 if (base.LoaderHost != null && base.LoaderHost.Container.Components[name] != null) {
231 valid = false;
232 } else {
233 if (this.CodeDomProvider != null) {
234 valid = CodeDomProvider.IsValidIdentifier (name);
235 } else {
236 if (name.Trim().Length == 0)
237 valid = false;
238 foreach (char c in name) {
239 if (!Char.IsLetterOrDigit (c)) {
240 valid = false;
241 break;
247 return valid;
250 void INameCreationService.ValidateName (string name)
252 if (!((INameCreationService) this).IsValidName (name))
253 throw new ArgumentException ("Invalid name '" + name + "'");
255 #endregion
258 #region IDesignerSerializationService implementation
260 ICollection IDesignerSerializationService.Deserialize (object serializationData)
262 if (serializationData == null)
263 throw new ArgumentNullException ("serializationData");
265 ComponentSerializationService service = LoaderHost.GetService (typeof (ComponentSerializationService)) as ComponentSerializationService;
266 SerializationStore store = serializationData as SerializationStore;
267 if (service != null && serializationData != null)
268 return service.Deserialize (store, this.LoaderHost.Container);
269 return new object[0];
272 object IDesignerSerializationService.Serialize (ICollection objects)
274 if (objects == null)
275 throw new ArgumentNullException ("objects");
277 ComponentSerializationService service = LoaderHost.GetService (typeof (ComponentSerializationService)) as ComponentSerializationService;
278 if (service != null) {
279 SerializationStore store = service.CreateStore ();
280 foreach (object o in objects)
281 service.Serialize (store, o);
282 store.Close ();
283 return store;
285 return null;
287 #endregion
291 #endif