fix #7989 - add support for extended classes (partial)
[roobuilder] / src / JsRender / NodeToValaExtended.vala
1 /*
2
3 This coverts nodes to vala code (but unlike the original) does it by extending the original wrapped class
4
5 */
6
7 public class  JsRender.NodeToValaExtended : NodeToVala {
8
9          
10          
11  
12         /* 
13          * ctor - just initializes things
14          * - wraps a render node 
15          */
16         public NodeToValaExtended( JsRender file,  Node node,  int depth, NodeToValaExtended? parent) 
17         {
18                 base (file, node, depth, parent);
19                 this.this_el = "this.";
20         }
21         /**
22          *  Main entry point to convert a file into a string..
23          */
24         public static string mungeFile(JsRender file) 
25         {
26                 if (file.tree == null) {
27                         return "";
28                 }
29
30                 var n = new NodeToValaExtended(file, file.tree, 0, null);
31                 n.toValaName(file.tree);
32                 
33                 
34                 GLib.debug("top cls %s / xlcs %s\n ",file.tree.xvala_cls,file.tree.xvala_cls); 
35                                 n.initCls();
36                 return n.munge();
37                 
38
39         }
40         int child_count = 1; // used to number the children.
41         public override string munge ( )
42         {
43                 //return this.mungeToString(this.node);
44                 this.child_count = 1;
45          
46                 
47                 this.namespaceHeader();
48
49                 this.classHeader();
50
51                 this.addTopProperties(); /// properties set with 'id'
52                 this.addMyVars(); // user defined properties.
53                 
54                 // skip '+' properties?? not sure where they are used.
55                 this.addValaCtor();
56  
57                  
58                 this.addInitMyVars();
59                 this.addWrappedProperties();
60                 this.addChildren(); // to constructor code
61                 //this.addSealedChildren();
62                 //this.addAutoShow(); // not needed gtk4 autoshow menuitems
63                 
64                 this.addInit();
65                 this.addListeners();
66                 this.addEndCtor();
67                 this.addUserMethods();
68                 this.iterChildren(); // add children class definitions.
69                 this.namespaceFooter();
70                 
71                 return this.ret;
72                  
73                          
74         } 
75         
76         public override string mungeChild(  Node cnode)
77         {
78                 var x = new  NodeToValaExtended(this.file, cnode,  this.depth+1, this);
79                 return x.munge();
80         }
81         
82         
83         protected override void classHeader()
84         {
85                            
86                 var top = this.top as NodeToVala;
87                 if (top == null) {
88                         return;
89                 }
90                 // class header..
91                 // class xxx {   WrappedGtk  el; }
92                 this.node.line_start = this.cur_line;
93                 
94                 this.top.node.setNodeLine(this.cur_line, this.node);
95                 
96                 this.addLine(this.inpad + "public class " + this.xcls + " : " + this.cls);
97                 this.addLine(this.inpad + "{");
98                 
99                 this.addLine(this.pad + "private " + top.xcls + "  _this;"); /// or protected??
100                 this.addLine();
101                         
102                         
103                         
104                         // singleton
105         }
106         
107         /**
108          * add the constructor definition..
109          * this probably has to match the parent constructor.. 
110          **?? NO SUPPORT FOR * ARGS?
111          ** for child elements we have to add '_owner to the ctor arguments.
112          for most elements we have to call object ( a: a, b: b)  if the parent requires properties..
113          eg. like Gtk.Box
114          
115          
116          */
117          
118         protected override void addValaCtor()
119         {
120                         
121                 
122                 
123                 var ncls = Palete.Gir.factoryFqn((Project.Gtk) this.file.project, this.node.fqn());
124                 if (ncls == null || ncls.nodetype != "Class") { 
125                         this.addLine(this.ipad + "** classname is invalid - can not make ctor "  + this.node.fqn());
126                         return;
127                 }
128                 var ctor = ".new";
129                 var default_ctor = Palete.Gir.factoryFqn((Project.Gtk) this.file.project, this.node.fqn() + ctor);              
130                 
131                 if (default_ctor == null) {
132                         this.addLine(this.ipad + "** classname is invalid - can not find ctor "  + this.node.fqn() + ".new");
133                         return;
134                 }
135                 // simple ctor...(will not need ctor params..
136                 
137                 
138                 // now we can skip ctor arguments if we have actually set them?
139                 string[] args  = {};
140                 if (default_ctor.paramset != null &&  default_ctor.paramset.params.size > 0)  {
141                         foreach(var param in default_ctor.paramset.params) {
142                                          
143                                 var n = param.name;
144                                 GLib.debug("building CTOR ARGS: %s, %s", n, param.is_varargs ? "VARARGS": "");
145                                 // not sure if it's even worth warning on this...
146                                 if (n == "___") { // for some reason our varargs are converted to '___' ...
147                                         continue;
148                                 }
149                                 if (this.node.has(n)) {
150                                         continue;
151                                 }
152                                 var propnode = this.node.findProp(n);
153                                 if (propnode != null) {
154                                         continue;
155                                 }
156                                 // finally      
157                                 args += (param.type + " " + n);
158                                   
159
160                         }
161                 }
162                 // create the ctor method
163                 
164  
165                 if (this.depth < 1) {
166                  
167                         // top level - does not pass the top level element..
168                         this.addLine(this.pad + "public " + this.xcls + "()");
169                         this.addLine(this.pad + "{");
170                            
171                 } else {
172                         var top = this.top as NodeToVala;
173                         var tcls = top == null ? "???" : top.xcls;
174                         args += (tcls + " _owner" );
175                                 // for sub classes = we passs the top level as _owner
176                         this.addLine(this.pad + "public " + this.xcls + "(" +  tcls + " _owner )");
177                         this.addLine(this.pad + "{");   
178                          
179                 }
180                 this.addUnderThis(); // set up '_this = _owner or _this = this;
181                 
182                 // if there are no ctor args, then we do not need to call object // or create props.
183                 if (default_ctor.paramset == null ||  default_ctor.paramset.params.size < 1)  {
184                         return;
185                 }
186                 // .vala props.. 
187                 var obj_args = new Gee.HashMap<string,string>();
188                 foreach(var param in default_ctor.paramset.params) {
189                         var n = param.name;
190                         if (n == "___") { // for some reason our varargs are converted to '___' ...
191                                         continue;
192                         }
193                         if (this.node.has(n)) {  // node does not have a value
194                                 
195                                 this.ignoreWrapped(n);
196                                 this.ignore(n);
197                                 
198                                 var v = this.node.get(n);
199
200                                 if (param.type == "string") {
201                                         v = "\"" +  v.escape("") + "\"";
202                                 }
203                                 if (v == "TRUE" || v == "FALSE") {
204                                         v = v.down();
205                                 }
206                                 obj_args.set(n, v);
207                                  
208                                 continue;
209                         }
210                         var propnode = this.node.findProp(n);
211                         if (propnode != null) {
212                                 // assume it's ok..
213                                 
214                                 var pname = this.addPropSet(propnode, propnode.has("id") ? propnode.get_prop("id").val : "");
215                                 obj_args.set(n, pname);
216                                  
217                                 if (!propnode.has("id")) {
218                                         this.addLine(this.ipad + pname +".ref();"); 
219                                 }
220                                  
221                                 this.ignoreWrapped(n); //??? not sure why we dont ignore it as well. 
222                                  
223                                 continue;
224                         }
225                 }
226                 if (obj_args.keys.size < 1) {
227                         return;
228                 }
229                 this.addLine(this.ipad + "Object(");
230                 // at this point we might have object...
231                 var ks = obj_args.keys.to_array();
232                 for(var i = 0; i < ks.length; i++ ) {
233                         var k = ks[i];
234                         var v = obj_args.get(k);
235                         this.addLine(this.ipad + "\t" + k + ": " + v + (i == (ks.length-1) ? "" : ","));
236                 }
237                 this.addLine(this.ipad + ");");
238
239         }
240         
241         
242          
243         
244 }