Merge pull request #1505 from esdrubal/tzifloatingrule
[mono.git] / mcs / class / System.Design / System.ComponentModel.Design.Serialization / RootCodeDomSerializer.cs
1 //
2 // System.ComponentModel.Design.Serialization.RootCodeDomSerializer
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
31 using System;
32 using System.Collections;
33 using System.Collections.Generic;
34 using System.ComponentModel;
35 using System.ComponentModel.Design;
36
37 using System.CodeDom;
38
39 namespace System.ComponentModel.Design.Serialization
40 {
41         internal class RootCodeDomSerializer : CodeDomSerializer
42         {
43
44                 internal class CodeMap
45                 {
46
47                         private string _className;
48                         private Type _classType;
49                         private List<CodeMemberField> _fields;
50                         private CodeStatementCollection _initializers;
51                         private CodeStatementCollection _begin;
52                         private CodeStatementCollection _default;
53                         private CodeStatementCollection _end;
54
55
56                         public CodeMap (Type classType, string className)
57                         {
58                                 if (classType == null)
59                                         throw new ArgumentNullException ("classType");
60                                 if (className == null)
61                                         throw new ArgumentNullException ("className");
62
63                                 _classType = classType;
64                                 _className = className;
65                                 _fields = new List<CodeMemberField> ();
66                                 _initializers = new CodeStatementCollection ();
67                                 _begin = new CodeStatementCollection ();
68                                 _default = new CodeStatementCollection ();
69                                 _end = new CodeStatementCollection ();
70                         }
71
72                         public void AddField (CodeMemberField field)
73                         {
74                                 _fields.Add (field);
75                         }
76
77                         public void Add (CodeStatementCollection statements)
78                         {
79                                 foreach (CodeStatement statement in statements)
80                                         this.Add (statement);
81                         }
82
83                         public void Add (CodeStatement statement)
84                         {
85                                 if (statement.UserData["statement-order"] == null)
86                                         _default.Add (statement);
87                                 else if ((string)statement.UserData["statement-order"] == "initializer")
88                                         _initializers.Add (statement);
89                                 else if ((string)statement.UserData["statement-order"] == "begin")
90                                         _begin.Add (statement);
91                                 else if ((string)statement.UserData["statement-order"] == "end")
92                                         _end.Add (statement);
93                         }
94
95                         /*
96                                 class Type : BaseType
97                                 {
98                                         #region Windows Form Designer generated code
99
100                                         private void InitializeComponent ()
101                                         {
102                                                 // statement-order:
103                                                 initializer
104                                                 pre-begin - e.g: // ComponentName
105                                                 begin - e.g: SuspendLayout
106                                                 default
107                                                 end - e.g: ResumeLayout
108                                                 post-end
109                                         }
110
111                                         private field1;
112                                         private field2;
113
114                                         #endregion
115                                 }
116                         */
117
118                         public CodeTypeDeclaration GenerateClass ()
119                         {
120                                 CodeTypeDeclaration clas = new CodeTypeDeclaration (_className);
121                                 clas.BaseTypes.Add (_classType);
122
123                                 clas.StartDirectives.Add (new CodeRegionDirective (CodeRegionMode.Start, "Windows Form Designer generated code"));
124
125                                 CodeMemberMethod initialize = new CodeMemberMethod ();
126                                 initialize.Name = "InitializeComponent";
127                                 initialize.ReturnType = new CodeTypeReference (typeof (void));
128                                 initialize.Attributes = MemberAttributes.Private;
129
130                                 initialize.Statements.AddRange (_initializers);
131                                 initialize.Statements.AddRange (_begin);
132                                 initialize.Statements.AddRange (_default);
133                                 initialize.Statements.AddRange (_end);
134
135                                 clas.Members.Add (initialize);
136
137                                 foreach (CodeMemberField field in _fields)
138                                         clas.Members.Add (field);
139
140                                 clas.EndDirectives.Add (new CodeRegionDirective (CodeRegionMode.End, null));
141
142                                 return clas;
143                         }
144
145                         public void Clear ()
146                         {
147                                 _fields.Clear ();
148                                 _initializers.Clear ();
149                                 _begin.Clear ();
150                                 _default.Clear ();
151                                 _end.Clear ();
152                         }
153                 }
154
155
156                 private CodeMap _codeMap;
157
158                 public RootCodeDomSerializer ()
159                 {
160                 }
161
162                 public override object Serialize (IDesignerSerializationManager manager, object value)
163                 {
164                         if (manager == null)
165                                 throw new ArgumentNullException ("manager");
166                         if (value == null)
167                                 throw new ArgumentNullException ("value");
168
169                         if (_codeMap == null)
170                                 _codeMap = new CodeMap (value.GetType (), manager.GetName (value));
171                         _codeMap.Clear ();
172
173                         RootContext rootContext = new RootContext (new CodeThisReferenceExpression (), value);
174                         manager.Context.Push (rootContext);
175
176                         this.SerializeComponents (manager, ((IComponent) value).Site.Container.Components, (IComponent) value);
177
178                         // Serialize root component
179                         // 
180                         CodeStatementCollection statements = new CodeStatementCollection ();
181                         statements.Add (new CodeCommentStatement (String.Empty));
182                         statements.Add (new CodeCommentStatement (manager.GetName (value)));
183                         statements.Add (new CodeCommentStatement (String.Empty));
184                         // Note that during the serialization process below ComponentCodeDomSerializer
185                         // will be invoked to serialize the rootcomponent during expression serialization.
186                         // It will check for RootContext and return that.
187                         base.SerializeProperties (manager, statements, value, new Attribute[0]);
188                         base.SerializeEvents (manager, statements, value, new Attribute[0]);
189                         _codeMap.Add (statements);
190
191                         manager.Context.Pop ();
192                         return _codeMap.GenerateClass ();
193                 }
194
195                 private void SerializeComponents (IDesignerSerializationManager manager, ICollection components, IComponent rootComponent)
196                 {
197                         foreach (IComponent component in components) {
198                                 if (!Object.ReferenceEquals (component, rootComponent))
199                                         SerializeComponent (manager, component);
200                         }
201                 }
202
203                 private void SerializeComponent (IDesignerSerializationManager manager, IComponent component)
204                 {
205                         CodeDomSerializer serializer = base.GetSerializer (manager, component) as CodeDomSerializer; // ComponentCodeDomSerializer
206                         if (serializer != null) {
207                                 this._codeMap.AddField (new CodeMemberField (component.GetType (), manager.GetName (component)));
208                                 // statements can be a CodeExpression if the full serialization has been completed prior 
209                                 // to this serialization call (e.g when it is requested during the serialization of another 
210                                 // component.
211                                 // 
212                                 CodeStatementCollection statements = serializer.Serialize (manager, component) as CodeStatementCollection;
213                                 if (statements != null)
214                                         _codeMap.Add (statements);
215                                 CodeStatement statement = serializer.Serialize (manager, component) as CodeStatement;
216                                 if (statement != null)
217                                         _codeMap.Add (statement);
218                         }
219                 }
220
221                 public override object Deserialize (IDesignerSerializationManager manager, object codeObject)
222                 {
223                         CodeTypeDeclaration declaration = (CodeTypeDeclaration) codeObject;
224                         Type rootType = manager.GetType (declaration.BaseTypes[0].BaseType);
225                         object root = manager.CreateInstance (rootType, null, declaration.Name, true);
226
227                         RootContext rootContext = new RootContext (new CodeThisReferenceExpression (), root);
228                         manager.Context.Push (rootContext);
229
230                         CodeMemberMethod initComponentMethod = GetInitializeMethod (declaration);
231                         if (initComponentMethod == null)
232                                 throw new InvalidOperationException ("InitializeComponent method is missing in: " + declaration.Name);
233
234                         foreach (CodeStatement statement in initComponentMethod.Statements)
235                                 base.DeserializeStatement (manager, statement);
236
237                         manager.Context.Pop ();
238                         return root;
239                 }
240
241                 private CodeMemberMethod GetInitializeMethod (CodeTypeDeclaration declaration)
242                 {
243                         CodeMemberMethod method = null;
244                         foreach (CodeTypeMember member in declaration.Members) {
245                                 method = member as CodeMemberMethod;
246                                 if (method != null && method.Name == "InitializeComponent")
247                                         break;
248                         }
249                         return method;
250                 }
251         }
252 }