2
using System.Reflection;
4
using System.CodeDom.Compiler;
5
using System.Collections.Generic;
7
using System.Collections;
11
internal static class CodeGenerator
13
public static void GenerateProjectCode (string file, CodeDomProvider provider, GenerationOptions options, ProjectBackend[] projects)
15
CodeGenerationResult res = GenerateProjectCode (options, projects);
17
ICodeGenerator gen = provider.CreateGenerator ();
18
string basePath = Path.GetDirectoryName (file);
20
foreach (SteticCompilationUnit unit in res.Units) {
22
if (unit.Name.Length == 0)
25
fname = Path.Combine (basePath, unit.Name);
26
StreamWriter fileStream = new StreamWriter (fname);
28
gen.GenerateCodeFromCompileUnit (unit, fileStream, new CodeGeneratorOptions ());
35
public static CodeGenerationResult GenerateProjectCode (GenerationOptions options, ProjectBackend[] projects)
37
ArrayList warningList = new ArrayList ();
39
List<SteticCompilationUnit> units = new List<SteticCompilationUnit> ();
40
SteticCompilationUnit globalUnit = new SteticCompilationUnit ("");
41
units.Add (globalUnit);
44
options = new GenerationOptions ();
45
CodeNamespace globalNs = new CodeNamespace (options.GlobalNamespace);
46
globalUnit.Namespaces.Add (globalNs);
50
CodeTypeDeclaration globalType = new CodeTypeDeclaration ("Gui");
51
globalType.Attributes = MemberAttributes.Private;
52
globalType.TypeAttributes = TypeAttributes.NestedAssembly;
53
globalNs.Types.Add (globalType);
55
// Create the project initialization method
56
// This method will only be added at the end if there
57
// is actually something to initialize
59
CodeMemberMethod initMethod = new CodeMemberMethod ();
60
initMethod.Name = "Initialize";
61
initMethod.ReturnType = new CodeTypeReference (typeof(void));
62
initMethod.Attributes = MemberAttributes.Assembly | MemberAttributes.Static;
63
initMethod.Parameters.Add (new CodeParameterDeclarationExpression (typeof(Gtk.Widget), "iconRenderer"));
65
GeneratorContext initContext = new ProjectGeneratorContext (globalNs, globalType, initMethod.Statements, options);
66
initContext.RootObject = new CodeArgumentReferenceExpression ("iconRenderer");
68
// Generate icon factory creation
70
foreach (ProjectBackend gp in projects) {
71
if (gp.IconFactory.Icons.Count > 0)
72
gp.IconFactory.GenerateBuildCode (initContext);
74
warningList.AddRange (initContext.Warnings);
78
if (options.UsePartialClasses)
79
CodeGeneratorPartialClass.GenerateProjectGuiCode (globalUnit, globalNs, globalType, options, units, projects, warningList);
81
CodeGeneratorInternalClass.GenerateProjectGuiCode (globalUnit, globalNs, globalType, options, units, projects, warningList);
83
GenerateProjectActionsCode (globalNs, options, projects);
85
// Final step. If there is some initialization code, add all needed infrastructure
87
globalType.Members.Add (initMethod);
89
CodeMemberField initField = new CodeMemberField (typeof(bool), "initialized");
90
initField.Attributes = MemberAttributes.Private | MemberAttributes.Static;
91
globalType.Members.Add (initField);
93
CodeFieldReferenceExpression initVar = new CodeFieldReferenceExpression (
94
new CodeTypeReferenceExpression (globalNs.Name + ".Gui"),
98
CodeConditionStatement initCondition = new CodeConditionStatement ();
99
initCondition.Condition = new CodeBinaryOperatorExpression (
101
CodeBinaryOperatorType.IdentityEquality,
102
new CodePrimitiveExpression (false)
104
initCondition.TrueStatements.Add (new CodeAssignStatement (
106
new CodePrimitiveExpression (true)
108
initCondition.TrueStatements.AddRange (initMethod.Statements);
109
initMethod.Statements.Clear ();
110
initMethod.Statements.Add (initCondition);
112
return new CodeGenerationResult (units.ToArray (), (string[]) warningList.ToArray (typeof(string)));
115
internal static void BindSignalHandlers (CodeExpression targetObjectVar, ObjectWrapper wrapper, Stetic.WidgetMap map, CodeStatementCollection statements, GenerationOptions options)
117
foreach (Signal signal in wrapper.Signals) {
118
SignalDescriptor descriptor = signal.SignalDescriptor;
120
CodeExpression createDelegate;
122
if (options.UsePartialClasses) {
124
new CodeDelegateCreateExpression (
125
new CodeTypeReference (descriptor.HandlerTypeName),
126
new CodeThisReferenceExpression (),
130
new CodeMethodInvokeExpression (
131
new CodeTypeReferenceExpression (typeof(Delegate)),
133
new CodeTypeOfExpression (descriptor.HandlerTypeName),
135
new CodePrimitiveExpression (signal.Handler));
137
createDelegate = new CodeCastExpression (descriptor.HandlerTypeName, createDelegate);
140
CodeAttachEventStatement cevent = new CodeAttachEventStatement (
141
new CodeEventReferenceExpression (
142
map.GetWidgetExp (wrapper),
146
statements.Add (cevent);
149
Wrapper.Widget widget = wrapper as Wrapper.Widget;
150
if (widget != null && widget.IsTopLevel) {
151
// Bind local action signals
152
foreach (Wrapper.ActionGroup grp in widget.LocalActionGroups) {
153
foreach (Wrapper.Action ac in grp.Actions)
154
BindSignalHandlers (targetObjectVar, ac, map, statements, options);
158
Gtk.Container cont = wrapper.Wrapped as Gtk.Container;
160
foreach (Gtk.Widget child in cont.AllChildren) {
161
Stetic.Wrapper.Widget ww = Stetic.Wrapper.Widget.Lookup (child);
163
BindSignalHandlers (targetObjectVar, ww, map, statements, options);
169
static void GenerateProjectActionsCode (CodeNamespace cns, GenerationOptions options, params ProjectBackend[] projects)
171
bool multiProject = projects.Length > 1;
173
CodeTypeDeclaration type = new CodeTypeDeclaration ("ActionGroups");
174
type.Attributes = MemberAttributes.Private;
175
type.TypeAttributes = TypeAttributes.NestedAssembly;
176
cns.Types.Add (type);
178
// Generate the global action group getter
180
CodeMemberMethod met = new CodeMemberMethod ();
181
met.Name = "GetActionGroup";
182
type.Members.Add (met);
183
met.Parameters.Add (new CodeParameterDeclarationExpression (typeof(Type), "type"));
185
met.Parameters.Add (new CodeParameterDeclarationExpression (typeof(string), "file"));
186
met.ReturnType = new CodeTypeReference (typeof(Gtk.ActionGroup));
187
met.Attributes = MemberAttributes.Public | MemberAttributes.Static;
189
CodeMethodInvokeExpression call = new CodeMethodInvokeExpression (
190
new CodeMethodReferenceExpression (
191
new CodeTypeReferenceExpression (cns.Name + ".ActionGroups"),
194
new CodePropertyReferenceExpression (
195
new CodeArgumentReferenceExpression ("type"),
200
call.Parameters.Add (new CodeArgumentReferenceExpression ("file"));
202
met.Statements.Add (new CodeMethodReturnStatement (call));
204
// Generate the global action group getter (overload)
206
met = new CodeMemberMethod ();
207
met.Name = "GetActionGroup";
208
type.Members.Add (met);
209
met.Parameters.Add (new CodeParameterDeclarationExpression (typeof(string), "name"));
211
met.Parameters.Add (new CodeParameterDeclarationExpression (typeof(string), "file"));
212
met.ReturnType = new CodeTypeReference (typeof(Gtk.ActionGroup));
213
met.Attributes = MemberAttributes.Public | MemberAttributes.Static;
215
CodeArgumentReferenceExpression cfile = new CodeArgumentReferenceExpression ("file");
216
CodeArgumentReferenceExpression cid = new CodeArgumentReferenceExpression ("name");
218
CodeStatementCollection projectCol = met.Statements;
221
foreach (ProjectBackend gp in projects) {
223
CodeStatementCollection widgetCol;
226
CodeConditionStatement pcond = new CodeConditionStatement ();
227
pcond.Condition = new CodeBinaryOperatorExpression (
229
CodeBinaryOperatorType.IdentityEquality,
230
new CodePrimitiveExpression (gp.Id)
232
projectCol.Add (pcond);
234
widgetCol = pcond.TrueStatements;
235
projectCol = pcond.FalseStatements;
237
widgetCol = projectCol;
240
foreach (Wrapper.ActionGroup grp in gp.ActionGroups) {
241
string fname = "group" + (n++);
242
CodeMemberField grpField = new CodeMemberField (typeof(Gtk.ActionGroup), fname);
243
grpField.Attributes |= MemberAttributes.Static;
244
type.Members.Add (grpField);
245
CodeFieldReferenceExpression grpVar = new CodeFieldReferenceExpression (
246
new CodeTypeReferenceExpression (cns.Name + ".ActionGroups"),
250
CodeConditionStatement pcond = new CodeConditionStatement ();
251
pcond.Condition = new CodeBinaryOperatorExpression (
253
CodeBinaryOperatorType.IdentityEquality,
254
new CodePrimitiveExpression (grp.Name)
256
widgetCol.Add (pcond);
258
// If the group has not yet been created, create it
259
CodeConditionStatement pcondGrp = new CodeConditionStatement ();
260
pcondGrp.Condition = new CodeBinaryOperatorExpression (
262
CodeBinaryOperatorType.IdentityEquality,
263
new CodePrimitiveExpression (null)
266
pcondGrp.TrueStatements.Add (
267
new CodeAssignStatement (
269
new CodeObjectCreateExpression (grp.Name)
273
pcond.TrueStatements.Add (pcondGrp);
274
pcond.TrueStatements.Add (new CodeMethodReturnStatement (grpVar));
276
widgetCol = pcond.FalseStatements;
278
widgetCol.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (null)));
280
if (met.Statements.Count == 0)
281
met.Statements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (null)));
284
internal static List<ObjectBindInfo> GetFieldsToBind (ObjectWrapper wrapper)
286
List<ObjectBindInfo> tobind = new List<ObjectBindInfo> ();
287
GetFieldsToBind (tobind, wrapper);
291
static void GetFieldsToBind (List<ObjectBindInfo> tobind, ObjectWrapper wrapper)
293
string memberName = null;
295
if (wrapper is Wrapper.Widget) {
296
Wrapper.Widget ww = wrapper as Wrapper.Widget;
298
if (!ww.IsTopLevel && ww.InternalChildProperty == null && !ww.Unselectable)
299
memberName = ((Wrapper.Widget) wrapper).Wrapped.Name;
301
else if (wrapper is Wrapper.Action)
302
memberName = ((Wrapper.Action) wrapper).Name;
304
if (memberName != null) {
305
ObjectBindInfo binfo = new ObjectBindInfo (wrapper.WrappedTypeName, memberName);
309
Wrapper.ActionGroup agroup = wrapper as Wrapper.ActionGroup;
310
if (agroup != null) {
311
foreach (Wrapper.Action ac in agroup.Actions)
312
GetFieldsToBind (tobind, ac);
315
Wrapper.Widget widget = wrapper as Wrapper.Widget;
316
if (widget != null && widget.IsTopLevel) {
317
// Generate fields for local actions
318
foreach (Wrapper.ActionGroup grp in widget.LocalActionGroups) {
319
GetFieldsToBind (tobind, grp);
323
Gtk.Container cont = wrapper.Wrapped as Gtk.Container;
325
foreach (Gtk.Widget child in cont.AllChildren) {
326
Stetic.Wrapper.Widget ww = Stetic.Wrapper.Widget.Lookup (child);
328
GetFieldsToBind (tobind, ww);
333
public static WidgetMap GenerateCreationCode (CodeNamespace cns, CodeTypeDeclaration type, Gtk.Widget w, CodeExpression widgetVarExp, CodeStatementCollection statements, GenerationOptions options, ArrayList warnings)
335
statements.Add (new CodeCommentStatement ("Widget " + w.Name));
336
GeneratorContext ctx = new ProjectGeneratorContext (cns, type, statements, options);
337
Stetic.Wrapper.Widget ww = Stetic.Wrapper.Widget.Lookup (w);
338
ctx.GenerateCreationCode (ww, widgetVarExp);
339
ctx.EndGeneration ();
340
warnings.AddRange (ctx.Warnings);
341
return ctx.WidgetMap;
344
public static WidgetMap GenerateCreationCode (CodeNamespace cns, CodeTypeDeclaration type, Wrapper.ActionGroup grp, CodeExpression groupVarExp, CodeStatementCollection statements, GenerationOptions options, ArrayList warnings)
346
statements.Add (new CodeCommentStatement ("Action group " + grp.Name));
347
GeneratorContext ctx = new ProjectGeneratorContext (cns, type, statements, options);
348
ctx.GenerateCreationCode (grp, groupVarExp);
349
ctx.EndGeneration ();
350
warnings.AddRange (ctx.Warnings);
351
return ctx.WidgetMap;
355
class ProjectGeneratorContext: GeneratorContext
357
CodeTypeDeclaration type;
359
public ProjectGeneratorContext (CodeNamespace cns, CodeTypeDeclaration type, CodeStatementCollection statements, GenerationOptions options): base (cns, "w", statements, options)
364
public override CodeExpression GenerateInstanceExpression (ObjectWrapper wrapper, CodeExpression newObject)
366
string typeName = wrapper.WrappedTypeName;
367
string memberName = null;
368
if (wrapper is Wrapper.Widget)
369
memberName = ((Wrapper.Widget) wrapper).Wrapped.Name;
370
else if (wrapper is Wrapper.Action)
371
memberName = ((Wrapper.Action) wrapper).Name;
373
if (memberName == null)
374
return base.GenerateInstanceExpression (wrapper, newObject);
376
if (Options.UsePartialClasses) {
377
// Don't generate fields for top level widgets and for widgets accessible
378
// through other widget's properties
379
Wrapper.Widget ww = wrapper as Wrapper.Widget;
380
if (ww == null || (!ww.IsTopLevel && ww.InternalChildProperty == null && !ww.Unselectable)) {
382
new CodeMemberField (
387
CodeExpression var = new CodeFieldReferenceExpression (
388
new CodeThisReferenceExpression (),
393
new CodeAssignStatement (
401
return base.GenerateInstanceExpression (wrapper, newObject);
403
CodeExpression var = base.GenerateInstanceExpression (wrapper, newObject);
405
new CodeAssignStatement (
406
new CodeIndexerExpression (
407
new CodeVariableReferenceExpression ("bindings"),
408
new CodePrimitiveExpression (memberName)
419
public class SteticCompilationUnit: CodeCompileUnit
423
public SteticCompilationUnit (string name)
430
internal set { name = value; }