small fix
[mono.git] / mcs / class / System.Design / System.ComponentModel.Design.Serialization / CodeDomDesignerLoader.cs
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
8
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.
28 //
29
30 #if NET_2_0
31
32 using System;
33 using System.Collections;
34 using System.ComponentModel;
35 using System.ComponentModel.Design;
36
37 using System.CodeDom;
38 using System.CodeDom.Compiler;
39
40 namespace System.ComponentModel.Design.Serialization
41 {
42         public abstract class CodeDomDesignerLoader : BasicDesignerLoader, INameCreationService, IDesignerSerializationService
43         {
44                 private CodeDomSerializer _rootSerializer;
45
46                 protected CodeDomDesignerLoader ()
47                 {
48                 }
49
50                 protected override void Initialize ()
51                 {
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                         IDesignerSerializationManager manager = base.LoaderHost.GetService (typeof (IDesignerSerializationManager)) as IDesignerSerializationManager;
58                         if (manager != null)
59                                 manager.AddSerializationProvider (CodeDomSerializationProvider.Instance);
60                 }
61                 
62                 protected override bool IsReloadNeeded ()
63                 {
64                         if (this.CodeDomProvider is ICodeDomDesignerReload)
65                                 return ((ICodeDomDesignerReload) CodeDomProvider).ShouldReloadDesigner (Parse ());
66                         return base.IsReloadNeeded ();
67                 }
68
69                 protected override void PerformLoad (IDesignerSerializationManager manager)
70                 {
71                         if (manager == null)
72                                 throw new ArgumentNullException ("manager");
73
74                         CodeCompileUnit document = this.Parse ();
75                         if (document == null)
76                                 throw new NotSupportedException ("The language did not provide a code parser for this file");
77
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.");
82
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");
87
88                         _rootSerializer.Deserialize (manager, rootDocument);
89
90                         base.SetBaseComponentClassName (namespaceName + "." + rootDocument.Name);
91                 }
92
93                 private CodeTypeDeclaration GetFirstCodeTypeDecl (CodeCompileUnit document, out string namespaceName)
94                 {
95                         namespaceName = null;
96
97                         foreach (CodeNamespace namesp in document.Namespaces) {
98                                 foreach (CodeTypeDeclaration declaration in namesp.Types) {
99                                         if (declaration.IsClass) {
100                                                 namespaceName = namesp.Name;
101                                                 return declaration;
102                                         }
103                                 }
104                         }
105                         return null;
106                 }
107                 
108                 protected override void PerformFlush (IDesignerSerializationManager manager)
109                 {
110                         if (_rootSerializer != null) {
111                                 CodeTypeDeclaration typeDecl = (CodeTypeDeclaration) _rootSerializer.Serialize (manager, 
112                                                                                                                                                                                                 base.LoaderHost.RootComponent);
113                                 this.Write (MergeTypeDeclWithCompileUnit (typeDecl, this.Parse ()));
114                         }
115                 }
116
117                 // Will either add the class or replace an existing class
118                 // with the one from GenerateClass ()
119                 //
120                 private CodeCompileUnit MergeTypeDeclWithCompileUnit (CodeTypeDeclaration typeDecl, CodeCompileUnit unit)
121                 {
122                         CodeNamespace namespac = null;
123                         int typeIndex = -1;
124
125                         foreach (CodeNamespace namesp in unit.Namespaces) {
126                                 for (int i=0; i< namesp.Types.Count; i++) {
127                                         if (namesp.Types[i].IsClass) {
128                                                 typeIndex = i;
129                                                 namespac = namesp;
130                                         }
131                                 }
132                         }
133
134                         if (typeIndex != -1)
135                                 namespac.Types.RemoveAt (typeIndex);
136
137                         namespac.Types.Add (typeDecl);
138
139                         return unit;
140                 }
141
142                 protected override void OnBeginLoad ()
143                 {
144                         base.OnBeginLoad ();
145
146                         IComponentChangeService service = base.GetService (typeof (IComponentChangeService)) as IComponentChangeService;
147                         if (service != null)
148                                 service.ComponentRename += this.OnComponentRename_EventHandler;
149                 }
150                 
151                 protected override void OnBeginUnload ()
152                 {
153                         base.OnBeginUnload ();
154
155                         IComponentChangeService service = base.GetService (typeof (IComponentChangeService)) as IComponentChangeService;
156                         if (service != null)
157                                 service.ComponentRename -= this.OnComponentRename_EventHandler;
158                 }
159                 
160                 protected override void OnEndLoad (bool successful, ICollection errors)
161                 {
162                         base.OnEndLoad (successful, errors);
163                         // XXX: msdn says overriden
164                 }
165
166                 private void OnComponentRename_EventHandler (object sender, ComponentRenameEventArgs args)
167                 {
168                         this.OnComponentRename (args.Component, args.OldName, args.NewName);
169                 }
170
171                 // MSDN says that here one should raise ComponentRename event and that's nonsense.
172                 //
173                 protected virtual void OnComponentRename (object component, string oldName, string newName) 
174                 {
175                         // What shall we do with the drunken sailor,
176                         // what shall we do with the drunken sailor early in the morning?
177                 }
178
179                 protected abstract CodeDomProvider CodeDomProvider { get; }
180                 protected abstract ITypeResolutionService TypeResolutionService { get; }
181                 protected abstract CodeCompileUnit Parse ();
182                 protected abstract void Write (CodeCompileUnit unit);
183
184                 public override void Dispose ()
185                 {
186                         base.Dispose ();
187                 }
188
189 #region INameCreationService implementation
190
191                 // very simplistic implementation to generate names like "button1", "someControl2", etc
192                 //
193                 string INameCreationService.CreateName (IContainer container, Type dataType)
194                 {
195                         if (dataType == null)
196                                 throw new ArgumentNullException ("dataType");
197
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));
202
203                         int uniqueId = 1;
204                         bool unique = false;
205
206                         while (!unique) {
207                                 if (container != null && container.Components[name + uniqueId] != null) {
208                                         uniqueId++;
209                                 } else {
210                                         unique = true;
211                                         name = name + uniqueId;
212                                 }
213                         }
214
215                         if (this.CodeDomProvider != null)
216                                 name = CodeDomProvider.CreateValidIdentifier (name);
217
218                         return name;
219                 }
220
221                 bool INameCreationService.IsValidName (string name)
222                 {
223                         if (name == null)
224                                 throw new ArgumentNullException ("name");
225
226                         bool valid = true;
227                         if (base.LoaderHost != null && base.LoaderHost.Container.Components[name] != null) {
228                                 valid = false;
229                         } else {
230                                 if (this.CodeDomProvider != null) {
231                                         valid = CodeDomProvider.IsValidIdentifier (name);
232                                 } else {
233                                         if (name.Trim().Length == 0)
234                                                 valid = false;
235                                         foreach (char c in name) {
236                                                 if (!Char.IsLetterOrDigit (c)) {
237                                                         valid = false;
238                                                         break;
239                                                 }
240                                         }
241                                 }
242                         }
243
244                         return valid;
245                 }
246
247                 void INameCreationService.ValidateName (string name)
248                 {
249                         if (!((INameCreationService) this).IsValidName (name))
250                                 throw new ArgumentException ("Invalid name '" + name + "'");
251                 }
252 #endregion
253
254
255 #region IDesignerSerializationService implementation
256
257                 ICollection IDesignerSerializationService.Deserialize (object serializationData)
258                 {
259                         if (serializationData == null)
260                                 throw new ArgumentNullException ("serializationData");
261
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];
267                 }
268
269                 object IDesignerSerializationService.Serialize (ICollection objects)
270                 {
271                         if (objects == null)
272                                 throw new ArgumentNullException ("objects");
273
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);
279                                 store.Close ();
280                                 return store;
281                         }
282                         return null;
283                 }
284 #endregion
285         }
286 }
287
288 #endif