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