meson.build.o7QLX02
[roobuilder] / src / JsRender / NodeToVala.vala
1 /**
2  * 
3  * Code to convert node tree to Vala...
4  * 
5  * usage : x = (new JsRender.NodeToVala(node)).munge();
6  * 
7  * Fixmes?
8  *
9  *  pack - can we come up with a replacement?
10      - parent.child == child_widget -- actually uses getters and effectively does 'add'?
11        (works on most)?
12     
13      
14  * args  -- vala constructor args (should really only be used at top level - we did use it for clutter originally(
15  * ctor  -- different ctor argument
16  
17  * 
18  
19  * 
20  * 
21 */
22
23  
24 public class JsRender.NodeToVala : Object {
25
26         Node node;
27
28         int depth;
29         string inpad;
30         string pad;
31         string ipad;
32         string cls;  // node fqn()
33         string xcls;
34         
35         string ret;
36         
37         int cur_line;
38
39         Gee.ArrayList<string> ignoreList;
40         Gee.ArrayList<string> ignoreWrappedList; 
41         Gee.ArrayList<string> myvars;
42         Gee.ArrayList<Node> vitems; // top level items
43         NodeToVala top;
44         JsRender file;
45         int pane_number = 0;
46         
47         /* 
48          * ctor - just initializes things
49          * - wraps a render node 
50          */
51         public NodeToVala( JsRender file,  Node node,  int depth, NodeToVala? parent) 
52         {
53
54                 
55                 this.node = node;
56                 this.depth = depth;
57                 if (file.name.contains(".")) { // namespaced..
58                         this.inpad = string.nfill(depth > 0 ? 2 : 1, '\t');
59                 } else {
60                         this.inpad = string.nfill(depth > 0 ? 1 : 0, '\t');
61                 }
62                 this.pad = this.inpad + "\t";
63                 this.ipad = this.inpad + "\t\t";
64                 this.cls = node.xvala_cls;
65                 this.xcls = node.xvala_xcls;
66                 if (depth == 0 && this.xcls.contains(".")) {
67                         var ar = this.xcls.split(".");
68                         this.xcls = ar[ar.length-1];
69                 }
70                 
71                 
72                 this.ret = "";
73                 this.cur_line = parent == null ? 0 : parent.cur_line;
74                 
75                 
76                 this.top = parent == null ? this : parent.top;
77                 this.ignoreList = new Gee.ArrayList<string>();
78                 this.ignoreWrappedList  = new Gee.ArrayList<string>();
79                 this.myvars = new Gee.ArrayList<string>();
80                 this.vitems = new Gee.ArrayList<Node>();
81                 this.file = file;
82                 
83                 // initialize line data..
84                 node.line_start = this.cur_line;
85                 node.line_end  = this.cur_line;
86                 node.lines = new Gee.ArrayList<int>();
87                 node.line_map = new Gee.HashMap<int,string>();
88                 if (parent == null) {
89                         node.node_lines = new Gee.ArrayList<int>();
90                         node.node_lines_map = new Gee.HashMap<int,Node>();
91                  }
92                 
93         }
94
95         public int vcnt = 0;
96         string toValaNS(Node item)
97         {
98                 var ns = item.get("xns") ;
99                 //if (ns == "GtkSource") {  technically on Gtk3?
100                 //      return "Gtk.Source";
101                 //}
102                 return ns + ".";
103         }
104         public void  toValaName(Node item, int depth =0) 
105         {
106                 this.vcnt++;
107
108                 var ns =  this.toValaNS(item) ;
109                 var cls = ns + item.get("xtype");
110                 
111                 
112                 item.xvala_cls = cls;
113                 
114                 
115                 string id = item.get("id").length > 0 ?
116                         item.get("id") :  "%s%d".printf(item.get("xtype"), this.vcnt);
117
118                 
119                 
120                 
121                 if (id[0] == '*' || id[0] == '+') {
122                         item.xvala_xcls = "Xcls_" + id.substring(1);
123                 } else {
124                         item.xvala_xcls = "Xcls_" + id;
125                 }
126                         
127                 
128                 item.xvala_id =  id;
129                 if (depth > 0) {                        
130                         this.vitems.add(item);
131                         
132                 // setting id on top level class changes it classname..                 
133                 // oddly enough we havent really thought about namespacing here.
134                 
135                 } else if (!item.props.has_key("id")) { 
136                         // use the file name..
137                         item.xvala_xcls =  this.file.file_without_namespace;
138                         // is id used?
139                         item.xvala_id = this.file.file_without_namespace;
140
141                 }
142                 // loop children..
143                                                                                                                            
144                 if (item.readItems().size < 1) {
145                         return;
146                 }
147                 for(var i =0;i<item.readItems().size;i++) {
148                         this.toValaName(item.readItems().get(i), depth+1);
149                 }
150                                           
151         }
152         /**
153          *  Main entry point to convert a file into a string..
154          */
155         public static string mungeFile(JsRender file) 
156         {
157                 if (file.tree == null) {
158                         return "";
159                 }
160
161                 var n = new NodeToVala(file, file.tree, 0, null);
162                 n.file = file;
163                 n.vcnt = 0;
164                 
165                 n.toValaName(file.tree);
166                 
167                 
168                 GLib.debug("top cls %s / xlcs %s\n ",file.tree.xvala_cls,file.tree.xvala_cls); 
169                 n.cls = file.tree.xvala_cls;
170                 n.xcls = file.tree.xvala_xcls;
171                 return n.munge();
172                 
173
174         }
175         int child_count = 1; // used to number the children.
176         public string munge ( )
177         {
178                 //return this.mungeToString(this.node);
179                 this.child_count = 1;
180                 this.ignore("pack");
181                 this.ignore("init");
182                 this.ignore("xns");
183                 this.ignore("xtype");
184                 this.ignore("id");
185                 
186                 this.namespaceHeader();
187                 this.globalVars();
188                 this.classHeader();
189                 this.addSingleton();
190                 this.addTopProperties();
191                 this.addMyVars();
192                 this.addPlusProperties();
193                 this.addValaCtor();
194                 this.addUnderThis();
195                 this.addWrappedCtor();  // var this.el = new XXXXX()
196
197                 this.addInitMyVars();
198                 this.addWrappedProperties();
199                 this.addChildren();
200                 this.addAutoShow(); // autoshow menuitems
201                 
202                 this.addInit();
203                 this.addListeners();
204                 this.addEndCtor();
205                 this.addUserMethods();
206                 this.iterChildren();
207                 this.namespaceFooter();
208                 
209                 return this.ret;
210                  
211                          
212         } 
213         public string mungeChild(  Node cnode)
214         {
215                 var x = new  NodeToVala(this.file, cnode,  this.depth+1, this);
216                 return x.munge();
217         }
218         public void addLine(string str= "")
219         {
220                 
221                 if (str.contains("\n")) {
222                         this.addMultiLine(str);
223                         return;
224                 }
225                 this.cur_line++;
226                 if (BuilderApplication.opt_bjs_compile != null) {
227                         this.ret += "/*%d*/ ".printf(this.cur_line) + str + "\n";
228                 } else {
229                         this.ret += str + "\n";
230                 }
231         }
232         public void addMultiLine(string str= "")
233         {
234                  
235                 this.cur_line += str.split("\n").length;
236                 //this.ret +=  "/*%d*/ ".printf(l) + str + "\n";
237                 this.ret +=   str + "\n";
238         }
239          
240         public void namespaceHeader()
241         {
242                 if (this.depth > 0 || this.file.file_namespace == "") {
243                         return;
244                 }
245                 this.addLine("namespace " + this.file.file_namespace);
246                 this.addLine("{");
247         
248         }
249         public void namespaceFooter()
250         {
251                 if (this.depth > 0 || this.file.file_namespace == "") {
252                         return;
253                 }
254                 this.addLine("}");
255         
256         }
257         public void globalVars()
258         {
259                 if (this.depth > 0) {
260                         return;
261                 }
262                 // Global Vars..??? when did this get removed..?
263                 //this.ret += this.inpad + "public static " + this.xcls + "  " + this.node.xvala_id+ ";\n\n";
264
265                 this.addLine(this.inpad + "static " + this.xcls + "  _" + this.node.xvala_id+ ";");
266                 this.addLine();
267                    
268         }
269
270         void classHeader()
271         {
272                            
273                 // class header..
274                 // class xxx {   WrappedGtk  el; }
275                 this.node.line_start = this.cur_line;
276                 
277                 this.top.node.setNodeLine(this.cur_line, this.node);
278                 
279                 this.addLine(this.inpad + "public class " + this.xcls + " : Object");
280                 this.addLine(this.inpad + "{");
281                 
282                  
283                 this.addLine(this.pad + "public " + this.cls + " el;");
284  
285                 this.addLine(this.pad + "private " + this.top.xcls + "  _this;");
286                 this.addLine();
287                         
288                         
289                         
290                         // singleton
291         }
292         void addSingleton() 
293         {
294                 if (depth > 0) {
295                         return;
296                 }
297                 this.addLine(pad + "public static " + xcls + " singleton()");
298                 this.addLine(this.pad + "{");
299                 this.addLine(this.ipad +    "if (_" + this.node.xvala_id  + " == null) {");
300                 this.addLine(this.ipad +    "    _" + this.node.xvala_id + "= new "+ this.xcls + "();");  // what about args?
301                 this.addLine(this.ipad +    "}");
302                 this.addLine(this.ipad +    "return _" + this.node.xvala_id +";");
303                 this.addLine(this.pad + "}");
304         }
305                         
306         /**
307          * when ID is used... on an element, it registeres a property on the top level...
308          * so that _this.ID always works..
309          * 
310          */
311         void addTopProperties()
312         {
313                 if (this.depth > 0) {
314                         return;
315                 }
316                 // properties - global..??
317
318                 var iter = this.vitems.list_iterator();
319                 while(iter.next()) {
320                         var n = iter.get();
321
322                          
323                         if (!n.props.has_key("id") || n.xvala_id.length < 0) {
324                                 continue;
325                                 
326                         }
327                         if (n.xvala_id[0] == '*') {
328                                 continue;
329                         }
330                         if (n.xvala_id[0] == '+') {
331                                 continue;
332                         }
333                         this.addLine(this.pad + "public " + n.xvala_xcls + " " + n.xvala_id + ";");
334                         
335                 }
336                                 
337         }
338         /**
339          * create properties that are not 'part of the wrapped element.
340          * 
341          * 
342          */
343  
344         void addMyVars()
345         {
346                 GLib.debug("callinged addMhyVars");
347                 
348                 this.addLine();
349                 this.addLine(this.ipad + "// my vars (def)");
350                         
351
352  
353                 var cls = Palete.Gir.factoryFqn((Project.Gtk) this.file.project, this.node.fqn());
354                    
355                 if (cls == null) {
356                         GLib.debug("Gir factory failed to find class %s", this.node.fqn());
357                         
358                         //return;
359                 }
360           
361                 
362                         // Key = TYPE:name
363                 var iter = this.node.props.map_iterator();
364                 while (iter.next()) {
365                          
366                         var prop = iter.get_value();
367                         
368                         if (this.shouldIgnore(prop.name)) {
369                                 continue;
370                         }
371
372                         // user defined method
373                         if (prop.ptype == NodePropType.METHOD) {
374                                 continue;
375                         }
376                         if (prop.ptype == NodePropType.SPECIAL) {
377                                 continue;
378                         }
379                                 
380                         if (prop.ptype == NodePropType.SIGNAL) {
381                                 this.node.setLine(this.cur_line, "p", prop.name);
382                                 this.addLine(this.pad + "public signal " + prop.rtype + " " + prop.name  + " "  + prop.val + ";");
383                                 
384                                 this.ignore(prop.name);
385                                 continue;
386                         }
387                         
388                         GLib.debug("Got myvars: %s", prop.name.strip());
389                         
390                         if (prop.rtype.strip().length < 1) {
391                                 continue;
392                         }
393                         
394                         // is it a class property...
395                         if (cls != null && cls.props.has_key(prop.name) && prop.ptype != NodePropType.USER) {
396                                 continue;
397                         }
398                         
399                         this.myvars.add(prop.name);
400                         prop.start_line = this.cur_line;
401                         
402                         this.node.setLine(this.cur_line, "p", prop.name);
403                         
404                         this.addLine(this.pad + "public " + prop.rtype + " " + prop.name + ";"); // definer - does not include value.
405
406
407                         prop.end_line = this.cur_line;                          
408                         this.ignore(prop.name);
409                         
410                                 
411                 }
412         }
413         
414         // if id of child is '+' then it's a property of this..
415         void addPlusProperties()
416         {
417                 if (this.node.readItems().size < 1) {
418                         return;
419                 }
420                 var iter = this.node.readItems().list_iterator();
421                 while (iter.next()) {
422                         var ci = iter.get();
423                                 
424                         if (ci.xvala_id[0] != '+') {
425                                 continue; // skip generation of children?
426                                 
427                         }
428                          
429                         this.addLine(this.pad + "public " + ci.xvala_xcls + " " + ci.xvala_id.substring(1) + ";");
430                                            
431                         
432                 }
433         }
434         /**
435          * add the constructor definition..
436          */
437         void addValaCtor()
438         {
439                         
440                 
441                 // .vala props.. 
442                 
443  
444                 var cargs_str = "";
445                 // ctor..
446                 this.addLine();
447                 this.addLine(this.pad + "// ctor");
448                 
449                 if (this.node.has("* args")) {
450                         // not sure what this is supposed to be ding..
451                 
452                         cargs_str =  this.node.get("* args");
453                         //var ar = this.node.get("* args");.split(",");
454                         //for (var ari =0; ari < ar.length; ari++) {
455                                 //      cargs +=  (ar[ari].trim().split(" ").pop();
456                                   // }
457                         }
458         
459                 if (this.depth < 1) {
460                  
461                         // top level - does not pass the top level element..
462                         this.addLine(this.pad + "public " + this.xcls + "(" +  cargs_str +")");
463                         this.addLine(this.pad + "{");
464                 } else {
465                         if (cargs_str.length > 0) {
466                                 cargs_str = ", " + cargs_str;
467                         }
468                         // for sub classes = we passs the top level as _owner
469                         this.addLine(this.pad + "public " + this.xcls + "(" +  this.top.xcls + " _owner " + cargs_str + ")");
470                         this.addLine(this.pad + "{");
471                 }
472                 
473
474         }
475         /**
476          *  make sure _this is defined..
477          */
478         void addUnderThis() 
479         {
480                 // public static?
481                 if (depth < 1) {
482                         this.addLine( this.ipad + "_this = this;");
483                         return;
484                 }
485                 // for non top level = _this point to owner, and _this.ID is set
486                 
487                 this.addLine( this.ipad + "_this = _owner;");
488
489                 if (this.node.props.has_key("id")
490                         &&
491                         this.node.xvala_id != "" 
492                         && 
493                         this.node.xvala_id[0] != '*' 
494                         && 
495                         this.node.xvala_id[0] != '+' 
496                         ) {
497                                 this.addLine( this.ipad + "_this." + node.xvala_id  + " = this;");
498                    
499                 }
500                          
501         }
502          
503         /**
504          * Initialize this.el to point to the wrapped element.
505          * 
506          * 
507          */
508
509         void addWrappedCtor()
510         {
511                 // wrapped ctor..
512                 // this may need to look up properties to fill in the arguments..
513                 // introspection does not workk..... - as things like gtkmessagedialog
514                 /*
515                 if (cls == 'Gtk.Table') {
516
517                 var methods = this.palete.getPropertiesFor(cls, 'methods');
518
519                 print(JSON.stringify(this.palete.proplist[cls], null,4));
520                 Seed.quit();
521                 }
522                 */
523                 
524                 // ctor can still override.
525                 if (this.node.has("* ctor")) {
526                         this.node.setLine(this.cur_line, "p", "* ctor");
527                         this.addLine(this.ipad + "this.el = " + this.node.get("* ctor")+ ";");
528                         return;
529                 }
530                 
531                 this.node.setLine(this.cur_line, "p", "* xtype");;
532                 
533                 // is the wrapped element a struct?
534                 
535                 var ncls = Palete.Gir.factoryFqn((Project.Gtk) this.file.project, this.node.fqn());
536                 if (ncls != null && ncls.nodetype == "Struct") {
537                         // we can use regular setters to apply the values.
538                         this.addLine(this.ipad + "this.el = " + this.node.fqn() + "();");
539                         return;
540                 
541                 
542                 }
543
544                 var ctor = ".new";
545                 var args_str = "";
546                 switch(this.node.fqn()) {
547                 
548                 // FIXME -- these are all GTK3 - can be removed when I get rid of them..
549                         case "Gtk.ComboBox":
550                                 var is_entry = this.node.has("has_entry") && this.node.get_prop("has_entry").val.down() == "true";
551                                 if (!is_entry) { 
552                                         break; // regular ctor.
553                                 }
554                                 this.ignoreWrapped("has_entry");
555                                 ctor = ".with_entry";
556                                 break;
557                                 
558                 
559                         case "Gtk.ListStore":
560                         case "Gtk.TreeStore":
561
562                                 // not sure if this works.. otherwise we have to go with varargs and count + vals...
563                                 if (this.node.has("* types")) {
564                                         args_str = this.node.get_prop("* types").val;
565                                 }
566                                 if (this.node.has("n_columns") && this.node.has("columns")) { // old value?
567                                         args_str = " { " + this.node.get_prop("columns").val + " } ";
568                                         this.ignoreWrapped("columns");
569                                         this.ignoreWrapped("n_columns");
570                                 }
571                                 
572                                 this.addLine(this.ipad + "this.el = new " + this.node.fqn() + ".newv( " + args_str + " );");
573                                 return;
574  
575                                 
576                         case "Gtk.LinkButton": // args filled with values.
577                                 if (this.node.has("label")) {
578                                         ctor = ".with_label";    
579                                 }
580                                 break;
581                                 
582                         default:
583                                 break;
584                 }
585                 var default_ctor = Palete.Gir.factoryFqn((Project.Gtk) this.file.project, this.node.fqn() + ctor);              
586                  
587                 
588                 // use the default ctor - with arguments (from properties)
589                 
590                 if (default_ctor != null && default_ctor.paramset != null && default_ctor.paramset.params.size > 0) {
591                         string[] args  = {};
592                         foreach(var param in default_ctor.paramset.params) {
593                                  
594                                 var n = param.name;
595                             GLib.debug("building CTOR ARGS: %s, %s", n, param.is_varargs ? "VARARGS": "");
596                                 if (n == "___") { // for some reason our varargs are converted to '___' ...
597                                         continue;
598                                 }
599                                 
600                                 if (this.node.has(n)) {  // node does not have a value
601                                         
602                                         this.ignoreWrapped(n);
603                                         this.ignore(n);
604                                         
605                                         var v = this.node.get(n);
606
607                                         if (param.type == "string") {
608                                                 v = "\"" +  v.escape("") + "\"";
609                                         }
610                                         if (v == "TRUE" || v == "FALSE") {
611                                                 v = v.down();
612                                         }
613
614                                         
615                                         args += v;
616                                         continue;
617                                 }
618                                 var propnode = this.node.findProp(n);
619                                 if (propnode != null) {
620                                         // assume it's ok..
621                                         
622                                         var pname = this.addPropSet(propnode, propnode.has("id") ? propnode.get_prop("id").val : "");
623                                         args += (pname + ".el") ;
624                                         if (!propnode.has("id")) {
625                                                 this.addLine(this.ipad + pname +".ref();"); 
626                                         }
627                                         
628                                         
629                                         
630                                         this.ignoreWrapped(n);
631                                         
632                                         continue;
633                                 }
634                                         
635                                          
636                                         
637                                         
638                                  
639                                 if (param.type.contains("int")) {
640                                         args += "0";
641                                         continue;
642                                 }
643                                 if (param.type.contains("float")) {
644                                         args += "0f";
645                                         continue;
646                                 }
647                                 if (param.type.contains("bool")) {
648                                         args += "true"; // always default to true?
649                                         continue;
650                                 }
651                                 // any other types???
652                                 
653                                 
654                                 
655                                 
656                                 args += "null";
657                                  
658                                 
659
660                         }
661                         this.node.setLine(this.cur_line, "p", "* xtype");
662                         this.addLine(this.ipad + "this.el = new " + this.node.fqn() + "( "+ string.joinv(", ",args) + " );") ;
663                         return;
664                         
665                 }
666                 // default ctor with no params..
667                  if (default_ctor != null && ctor != ".new" ) {
668                         this.node.setLine(this.cur_line, "p", "* xtype");
669                         
670                         this.addLine(this.ipad + "this.el = new " + this.node.fqn() + ctor + "(  );") ;
671                         return;
672                  }
673                 
674                 
675                 this.addLine(this.ipad + "this.el = new " + this.node.fqn() + "(" + args_str + ");");
676                 
677                 
678
679                         
680         }
681         public static Gee.ArrayList<string> menuitem_children = null;
682         
683         void addAutoShow()
684         {
685                 if (menuitem_children == null) {
686                         menuitem_children = new Gee.ArrayList<string>();
687                         menuitem_children.add("Gtk.MenuItem");
688                         var gir = this.file.project.palete.getClass("Gtk.MenuItem");
689                         if (gir != null) {
690                             foreach(var impl in gir.implementations) {
691                                     menuitem_children.add(impl);
692                             }
693                     }
694                 }
695
696                 if (menuitem_children.contains(this.node.fqn())) {
697                         this.addLine(this.ipad + "this.el.show();");
698                 
699                 }
700         }
701
702         void addInitMyVars()
703         {
704                         //var meths = this.palete.getPropertiesFor(item['|xns'] + '.' + item.xtype, 'methods');
705                         //print(JSON.stringify(meths,null,4));Seed.quit();
706                         
707                         
708                         
709                         // initialize.. my vars..
710                 this.addLine();
711                 this.addLine( this.ipad + "// my vars (dec)");
712                 
713                 var iter = this.myvars.list_iterator();
714                 while(iter.next()) {
715                         
716                         var k = iter.get();
717                         
718                          
719                         var prop = this.node.props.get(k);
720                         
721                         var v = prop.val.strip();                       
722                         
723                         if (v.length < 1) {
724                                 continue; 
725                         }
726                         // at this point start using 
727
728                         if (v == "FALSE" || v == "TRUE") {
729                                 v= v.down();
730                         }
731                         //FIXME -- check for raw string.. "string XXXX"
732                         
733                         // if it's a string...
734                         
735                         prop.start_line = this.cur_line;
736                         this.addLine(this.ipad + "this." + prop.name + " = " +   v +";");
737                         prop.end_line = this.cur_line;
738                 }
739         }
740
741         
742
743
744         
745         void addWrappedProperties()
746         {
747                 var cls = Palete.Gir.factoryFqn((Project.Gtk) this.file.project, this.node.fqn());
748                 if (cls == null) {
749                         GLib.debug("Skipping wrapped properties - could not find class  %s" , this.node.fqn());
750                         return;
751                 }
752                         // what are the properties of this class???
753                 this.addLine();
754                 this.addLine(this.ipad + "// set gobject values");
755                 
756
757                 var iter = cls.props.map_iterator();
758                 while (iter.next()) {
759                         var p = iter.get_key();
760                         //print("Check Write %s\n", p);
761                         if (!this.node.has(p)) {
762                                 continue;
763                         }
764                         if (this.shouldIgnoreWrapped(p)) {
765                                 continue;
766                         }
767                         
768                         this.ignore(p);
769
770
771                         var prop = this.node.get_prop(p);
772                         var v = prop.val;
773                         
774                         // user defined properties.
775                         if (prop.ptype == NodePropType.USER) {
776                                 continue;
777                         }
778                                 
779
780                         
781                         var is_raw = prop.ptype == NodePropType.RAW;
782                         
783                         // what's the type.. - if it's a string.. then we quote it..
784                         if (iter.get_value().type == "string" && !is_raw) {
785                                  v = "\"" +  v.escape("") + "\"";
786                         }
787                         if (v == "TRUE" || v == "FALSE") {
788                                 v = v.down();
789                         }
790                         if (iter.get_value().type == "float" && v[v.length-1] != 'f') {
791                                 v += "f";
792                         }
793                         
794                         prop.start_line = this.cur_line;
795                         this.addLine("%sthis.el.%s = %s;".printf(ipad,p,v)); // // %s,  iter.get_value().type);
796                         prop.end_line = this.cur_line;          
797                            // got a property..
798                            
799
800                 }
801                 
802         }
803         /**
804          *  pack the children into the parent.
805          * 
806          * if the child's id starts with '*' then it is not packed...
807          * - this allows you to define children and add them manually..
808          */
809
810         void addChildren()
811         {
812                                 //code
813                 if (this.node.readItems().size < 1) {
814                         return;
815                 }
816                 this.pane_number = 0;
817                 var cols = this.node.has("* columns") ? int.max(1, int.parse(this.node.get_prop("* columns").val)) : 1;
818                 var colpos = 0;
819                 
820  
821                  
822                 foreach(var child in this.node.readItems()) {
823                         
824                         
825                          
826
827                         if (child.xvala_id[0] == '*') {
828                                 continue; // skip generation of children?
829                         }
830
831                         // probably added in ctor..                             
832                         if (child.has("* prop") && this.shouldIgnoreWrapped(child.get_prop("* prop").val)) {
833                                 continue;
834                         }
835                         // create the element..
836                         
837                         // this is only needed if it does not have an ID???
838                         var childname = this.addPropSet(child, child.has("id") ? child.get_prop("id").val : "") ; 
839                         
840                         if (child.has("* prop")) {
841                          
842                         
843                                 // fixme special packing!??!?!
844                                 if (child.get_prop("* prop").val.contains("[]")) {
845                                         // currently these 'child props
846                                         // used for label[]  on Notebook
847                                         // used for button[]  on Dialog?
848                                         // columns[] ?
849                                          
850                                         this.packChild(child, childname, 0, 0, child.get_prop("* prop").val);  /// fixme - this is a bit speciall...
851                                         continue;
852                                 }
853                                 
854         
855                                 
856                                 this.ignoreWrapped(child.get_prop("* prop").val);
857                                 
858                                 this.addLine(ipad + "this.el." + child.get_prop("* prop").val + " = " + childname + ".el;");
859                                 continue;
860                         } 
861                          if (!child.has("id")) {
862                                 this.addLine(this.ipad + childname +".ref();"); 
863                          } 
864                         this.packChild(child, childname, cols, colpos);
865                         
866                         if (child.has("colspan")) {
867                                 colpos += int.parse(child.get_prop("colspan").val);
868                         } else {
869                                 colpos += 1;
870                         }
871                                           
872                         
873                         // this.{id - without the '+'} = the element...
874                          
875                                   
876                 }
877         }
878         
879         string addPropSet(Node child, string child_name) 
880         {
881          
882                 
883                 var xargs = "";
884                 if (child.has("* args")) {
885                         
886                         var ar = child.get_prop("* args").val.split(",");
887                         for (var ari = 0 ; ari < ar.length; ari++ ) {
888                                 var arg = ar[ari].split(" ");
889                                 xargs += "," + arg[arg.length -1];
890                         }
891                 }
892                 
893                 var childname = "child_" + "%d".printf(this.child_count++);     
894                 var prefix = "";
895                 if (child_name == "") {
896                         prefix = "var " + childname + " = ";
897                 }
898                 
899                 this.addLine(this.ipad +  prefix + "new " + child.xvala_xcls + "( _this " + xargs + ");" );
900                  
901                 // add a ref... (if 'id' is not set... to a '+' ?? what does that mean? - fake ids?
902                 // remove '+' support as I cant remember what it does!!!
903                 //if (child.xvala_id.length < 1 ) {
904                 //      this.addLine(this.ipad + childname +".ref();"); // we need to reference increase unnamed children...
905                 //}                     
906             //if (child.xvala_id[0] == '+') {
907                 //      this.addLine(this.ipad + "this." + child.xvala_id.substring(1) + " = " + childname+  ";");
908                                         
909                 //}
910                 
911
912                 return child_name == "" ? childname : ("_this." + child_name);  
913         }               
914                         
915         
916
917         
918         void packChild(Node child, string childname, int cols, int colpos, string propname= "")
919         {
920                 
921                 GLib.debug("packChild %s=>%s", this.node.fqn(), child.fqn());
922                 // forcing no packing? - true or false? -should we just accept false?
923                 if (child.has("* pack") && child.get("* pack").down() == "false") {
924                         return; // force no packing
925                 }
926                 if (child.has("* pack") && child.get("* pack").down() == "true") {
927                         return; // force no packing
928                 }
929                 
930                 // BC really - don't want to support this anymore.
931                 if (child.has("* pack")) {
932                         
933                         string[]  packing =  { "add" };
934                         if (child.has("* pack")) {
935                                 packing = child.get("* pack").split(",");
936                         }
937                         
938                         var pack = packing[0];
939                         this.addLine(this.ipad + "this.el." + pack.strip() + " ( " + childname + ".el " +
940                                    (packing.length > 1 ? 
941                                                 (", " + string.joinv(",", packing).substring(pack.length+1))
942                                         :
943                                                         ""
944                                                 ) + " );");
945                         return;  
946                 }
947                 var childcls =  this.file.project.palete.getClass(child.fqn()); // very trusting..
948                 if (childcls == null) {
949                   return;
950                 }
951                 // GTK4
952                 var is_event = childcls.inherits.contains("Gtk.EventController") || childcls.implements.contains("Gtk.EventController");
953                 if (is_event) {
954                     this.addLine(this.ipad + "this.el.add_controller(  %s.el );".printf(childname) );
955                     return;
956                 }
957                 
958                 
959                 switch (this.node.fqn()) {
960                         
961                                 
962                 
963                         case "Gtk.Fixed":
964                         case "Gtk.Layout":
965                                 var x = child.has("x") ?  child.get_prop("x").val  : "0";
966                                 var y = child.has("y") ?  child.get_prop("y").val  : "0";
967                                 this.addLine(this.ipad + "this.el.put( %s.el, %s, %s );".printf(childname,x,y) );
968                                 return;
969                                 
970                         
971
972                         case "Gtk.Stack":
973                                 var named = child.has("stack_name") ?  child.get_prop("stack_name").val.escape() : "";
974                                 var title = child.has("stack_title") ?  child.get_prop("stack_title").val.escape()  : "";
975                                 if (title.length > 0) {
976                                         this.addLine(this.ipad + "this.el.add_titled( %s.el, \"%s\", \"%s\" );".printf(childname,named,title)); 
977                                 } else {
978                                         this.addLine(this.ipad + "this.el.add_named( %s.el, \"%s\" );".printf(childname,named));
979                                 }
980                                 return;
981                                 
982                         case "Gtk.Notebook": // use label
983                                 var label = child.has("notebook_label") ?  child.get_prop("notebook_label").val.escape() : "";
984                                 this.addLine(this.ipad + "this.el.append_page( %s.el, new Gtk.Label(\"%s\"));".printf(childname, label));       
985                                 return;
986                                 
987                          
988                         case "Gtk.TreeView": // adding TreeViewColumns
989                                 this.addLine(this.ipad + "this.el.append_column( " + childname + ".el );");
990                                 return;
991                         
992                         case "Gtk.TreeViewColumn": //adding Renderers - I think these are all proprerties of the renderer used...
993                                 if (child.has("markup_column") && int.parse(child.get_prop("markup_column").val) > -1) {
994                                         this.addLine(this.ipad + "this.el.add_attribute( %s.el, \"markup\", %s );".printf(childname, child.get_prop("markup_column").val));
995                                 }
996                                 if (child.has("text_column") && int.parse(child.get_prop("text_column").val) > -1) {
997                                         this.addLine(this.ipad + "this.el.add_attribute(  %s.el, \"text\", %s );".printf(childname, child.get_prop("text_column").val));
998                                 }
999                                 if (child.has("pixbuf_column") && int.parse(child.get_prop("pixbuf_column").val) > -1) {
1000                                         this.addLine(this.ipad + "this.el.add_attribute(  %s.el, \"pixbuf\", %s );".printf(childname, child.get_prop("pixbuf_column").val));
1001                                 }
1002                                 if (child.has("pixbuf_column") && int.parse(child.get_prop("active_column").val) > -1) {
1003                                         this.addLine(this.ipad + "this.el.add_attribute(  %s.el, \"active\", %s );".printf(childname, child.get_prop("active_column").val));
1004                                 }
1005                                 if (child.has("background_column") && int.parse(child.get_prop("background_column").val) > -1) {
1006                                         this.addLine(this.ipad + "this.el.add_attribute(  %s.el, \"background-rgba\", %s );".printf(childname, child.get_prop("background_column").val));
1007                                 }
1008                                 this.addLine(this.ipad + "this.el.add( " + childname + ".el );");
1009                                 // any more!?
1010                                 return;
1011                         
1012                         case "Gtk.Dialog":
1013                                 if (propname == "buttons[]") {
1014                                         var resp_id = int.parse(childname.replace("child_", ""));
1015                                         if (child.has("* response_id")) { 
1016                                                 resp_id = int.parse(child.get_prop("* response_id").val);
1017                                         }
1018                                         this.addLine(this.ipad + "this.el.add_action_widget( %s.el, %d);".printf(childname,resp_id) );
1019                                         return;
1020                                 }
1021                         
1022                                 
1023                                 this.addLine(this.ipad + "this.el.get_content_area().add( " + childname + ".el );");
1024                                 return;
1025
1026                 
1027                                 
1028                         
1029         
1030         
1031         // known working with GTK4 !
1032                         case "Gtk.HeaderBar": // it could be end... - not sure how to hanle that other than overriding the pack method?
1033                                 this.addLine(this.ipad + "this.el.pack_start( "+ childname + ".el );");
1034                                 return;
1035                         
1036                         case "GLib.Menu":
1037                                 this.addLine(this.ipad + "this.el.append_item( "+ childname + ".el );");
1038                                 return; 
1039                         
1040                         case "Gtk.Paned":
1041                                 this.pane_number++;
1042                                 switch(this.pane_number) {
1043                                         case 1:
1044                                                 this.addLine(this.ipad + "this.el.pack_start( %s.el );".printf(childname));
1045                                                 return;
1046                                         case 2:                                 
1047                                                 this.addLine(this.ipad + "this.el.pack_end( %s.el );".printf(childname));
1048                                                 return;
1049                                         default:
1050                                                 // do nothing
1051                                                 break;
1052                                 }
1053                                 return;
1054                         
1055                         case "Gtk.ColumnView":
1056                                 this.addLine(this.ipad + "this.el.append_column( "+ childname + ".el );");
1057                                 return;
1058                         
1059                         case "Gtk.Grid":
1060                                 var x = "%d".printf(colpos % cols);
1061                                 var y = "%d".printf(( colpos - (colpos % cols) ) / cols);
1062                                 var w = child.has("colspan") ? child.get_prop("colspan").val : "1";
1063                                 var h = "1";
1064                                 this.addLine(this.ipad + "this.el.attach( %s.el, %s, %s, %s, %s );".printf(childname ,x,y, w, h) );
1065                                 return;
1066                         
1067                         default:
1068                             // gtk4 uses append!!!! - gtk3 - uses add..
1069                                 this.addLine(this.ipad + "this.el.append( "+ childname + ".el );");
1070                                 return;
1071                 
1072                 
1073                 }
1074                 
1075                 
1076         }
1077         
1078         // fixme GtkDialog?!? buttons[]
1079         
1080         // fixme ... add case "Gtk.RadioButton":  // group_id ??
1081
1082                         
1083
1084         void addInit()
1085         {
1086
1087                 
1088                 if (!this.node.has("* init")) {
1089                                 return;
1090                 }
1091                 this.addLine();
1092                 this.addLine(ipad + "// init method");
1093                 this.addLine();
1094                 this.node.setLine(this.cur_line, "p", "init");
1095                 
1096                 var init =  this.node.get_prop("* init");
1097                 init.start_line = this.cur_line;
1098                 this.addMultiLine(ipad + this.padMultiline(ipad, init.val) );
1099                 init.end_line = this.cur_line;
1100          }
1101          void addListeners()
1102          {
1103                 if (this.node.listeners.size < 1) {
1104                         return;
1105                 }
1106                                 
1107                 this.addLine();
1108                 this.addLine(ipad + "//listeners");
1109                         
1110                          
1111
1112                 var iter = this.node.listeners.map_iterator();
1113                 while (iter.next()) {
1114                         var k = iter.get_key();
1115                         var prop = iter.get_value();
1116                         var v = prop.val;
1117                         
1118                         prop.start_line = this.cur_line;
1119                         this.node.setLine(this.cur_line, "l", k);
1120                         this.addMultiLine(this.ipad + "this.el." + k + ".connect( " + 
1121                                         this.padMultiline(this.ipad,v) +");"); 
1122                         prop.end_line = this.cur_line;
1123                 }
1124         }    
1125         void addEndCtor()
1126         {
1127                          
1128                         // end ctor..
1129                         this.addLine(this.pad + "}");
1130         }
1131
1132
1133         /*
1134  * Standardize this crap...
1135  * 
1136  * standard properties (use to set)
1137  *          If they are long values show the dialog..
1138  *
1139  * someprop : ....
1140  * bool is_xxx  :: can show a pulldown.. (true/false)
1141  * string html  
1142  * $ string html  = string with value interpolated eg. baseURL + ".." 
1143  *  Clutter.ActorAlign x_align  (typed)  -- shows pulldowns if type is ENUM? 
1144  * $ untypedvalue = javascript untyped value...  
1145  * _ string html ... = translatable..
1146
1147  * 
1148  * object properties (not part of the GOjbect being wrapped?
1149  * # Gee.ArrayList<Xcls_fileitem> fileitems
1150  * 
1151  * signals
1152  * @ void open 
1153  * 
1154  * methods -- always text editor..
1155  * | void clearFiles
1156  * | someJSmethod
1157  * 
1158  * specials
1159  * * prop -- string
1160  * * args  -- string
1161  * * ctor -- string
1162  * * init -- big string?
1163  * 
1164  * event handlers (listeners)
1165  *   just shown 
1166  * 
1167  * -----------------
1168  * special ID values
1169  *  +XXXX -- indicates it's a instance property / not glob...
1170  *  *XXXX -- skip writing glob property (used as classes that can be created...)
1171  * 
1172  * 
1173  */
1174          
1175         void addUserMethods()
1176         {
1177                 this.addLine();
1178                 this.addLine(this.pad + "// user defined functions");
1179                         
1180                         // user defined functions...
1181                 var iter = this.node.props.map_iterator();
1182                 while(iter.next()) {
1183                         var prop = iter.get_value();
1184                         if (this.shouldIgnore(prop.name)) {
1185                                 continue;
1186                         }
1187                         // HOW TO DETERIME if its a method?            
1188                         if (prop.ptype != NodePropType.METHOD) {
1189                                         //strbuilder("\n" + pad + "// skip " + k + " - not pipe \n"); 
1190                                         continue;
1191                         }
1192                         
1193                         // function in the format of {type} (args) { .... }
1194
1195
1196
1197                         prop.start_line = this.cur_line;
1198                         this.node.setLine(this.cur_line, "p", prop.name);
1199                         this.addMultiLine(this.pad + "public " + prop.rtype + " " +  prop.name + " " + this.padMultiline(this.pad, prop.val));;
1200                         prop.end_line = this.cur_line;
1201                                 
1202                 }
1203         }
1204
1205         void iterChildren()
1206         {
1207                 this.node.line_end = this.cur_line;
1208                 this.node.sortLines();
1209                 
1210                         
1211                 if (this.depth > 0) {
1212                         this.addLine(this.inpad + "}");
1213                 }
1214                 
1215                 var iter = this.node.readItems().list_iterator();
1216                  
1217                 while (iter.next()) {
1218                         this.addMultiLine(this.mungeChild(iter.get()));
1219                 }
1220                          
1221                 if (this.depth < 1) {
1222                         this.addLine(this.inpad + "}");
1223                 }
1224                         
1225         }
1226
1227         string padMultiline(string pad, string str)
1228         {
1229                 var ar = str.strip().split("\n");
1230                 return string.joinv("\n" + pad , ar);
1231         }
1232         
1233         void ignore(string i) {
1234                 this.ignoreList.add(i);
1235                 
1236         }
1237         void ignoreWrapped(string i) {
1238                 this.ignoreWrappedList.add(i);
1239                 
1240         }
1241         bool shouldIgnore(string i)
1242         {
1243                 return ignoreList.contains(i);
1244         }
1245         bool shouldIgnoreWrapped(string i)
1246         {
1247                 return ignoreWrappedList.contains(i);
1248         }
1249         
1250 }
1251         
1252          
1253         
1254