3 * Code to convert node tree to Vala...
5 * usage : x = (new JsRender.NodeToVala(node)).munge();
9 * pack - can we come up with a replacement?
10 - parent.child == child_widget -- actually uses getters and effectively does 'add'?
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
24 public abstract class JsRender.NodeToVala : NodeWriter {
26 protected string this_el = "??";
28 int child_count = 1; // used to number the children.
29 public string cls; // node fqn()
33 Gee.ArrayList<string> ignoreWrappedList;
34 Gee.ArrayList<string> myvars;
38 int pane_number = 0;// ?? used when generating Gtk.Pane tabs
42 NodeWriter.globalIgnore("pack");
43 NodeWriter.globalIgnore("init");
44 NodeWriter.globalIgnore("xns");
45 NodeWriter.globalIgnore("xtype");
46 NodeWriter.globalIgnore("id");
50 * ctor - just initializes things
51 * - wraps a render node
53 protected NodeToVala( JsRender file, Node node, int depth, NodeToVala? parent)
56 base (file, node, depth, parent);
58 this.initPadding('\t', 1);
60 this.cls = node.xvala_cls;
61 this.xcls = node.xvala_xcls;
62 if (depth == 0 && this.xcls.contains(".")) {
63 var ar = this.xcls.split(".");
64 this.xcls = ar[ar.length-1];
68 this.ignoreWrappedList = new Gee.ArrayList<string>();
69 this.myvars = new Gee.ArrayList<string>();
76 this.cls = this.file.tree.xvala_cls;
77 this.xcls = this.file.tree.xvala_xcls;
79 public abstract string mungeChild( Node cnode);
82 public void namespaceHeader()
84 if (this.depth > 0 || this.file.file_namespace == "") {
87 this.addLine("namespace " + this.file.file_namespace);
91 public void namespaceFooter()
93 if (this.depth > 0 || this.file.file_namespace == "") {
101 protected abstract void classHeader();
106 * when ID is used... on an element, it registeres a property on the top level...
107 * so that _this.ID always works..
110 protected void addTopProperties()
112 if (this.depth > 0) {
115 // properties - global..??
116 foreach(var n in this.top_level_items) {
118 if (!n.props.has_key("id") || n.xvala_id.length < 0) {
122 if (n.xvala_id[0] == '*' || n.xvala_id[0] == '+') {
126 this.addLine(this.pad + "public " + n.xvala_xcls + " " + n.xvala_id + ";");
132 * create properties that are not 'part of the wrapped element.
137 protected void addMyVars()
139 GLib.debug("calling addMyVars");
142 this.addLine(this.ipad + "// my vars (def)");
146 var cls = Palete.Gir.factoryFqn((Project.Gtk) this.file.project, this.node.fqn());
149 GLib.debug("Gir factory failed to find class %s", this.node.fqn());
156 foreach(var prop in this.node.props.values) {
158 if (this.shouldIgnore(prop.name)) {
162 // user defined method
163 if (prop.ptype == NodePropType.METHOD) {
166 if (prop.ptype == NodePropType.SPECIAL) {
170 if (prop.ptype == NodePropType.SIGNAL) {
171 this.node.setLine(this.cur_line, "p", prop.name);
172 this.addLine(this.pad + "public signal " + prop.rtype + " " + prop.name + " " + prop.val + ";");
174 this.ignore(prop.name);
178 GLib.debug("Got myvars: %s", prop.name.strip());
180 if (prop.rtype.strip().length < 1) {
184 var isUser = prop.ptype == NodePropType.USER;
185 if (this.node.fqn() == "Gtk.NotebookPage") {
188 // is it a class property...
189 if (cls != null && cls.props.has_key(prop.name) && !isUser) {
193 this.myvars.add(prop.name);
194 prop.start_line = this.cur_line;
196 this.node.setLine(this.cur_line, "p", prop.name);
198 this.addLine(this.pad + "public " + prop.rtype + " " + prop.name + ";"); // definer - does not include value.
201 prop.end_line = this.cur_line;
202 this.ignore(prop.name);
208 // if id of child is '+' then it's a property of this..
209 protected void addPlusProperties()
211 if (this.node.readItems().size < 1) {
214 var iter = this.node.readItems().list_iterator();
215 while (iter.next()) {
218 if (ci.xvala_id[0] != '+') {
219 continue; // skip generation of children?
223 this.addLine(this.pad + "public " + ci.xvala_xcls + " " + ci.xvala_id.substring(1) + ";");
229 * add the constructor definition..
231 protected abstract void addValaCtor();
233 * make sure _this is defined..
235 protected void addUnderThis()
239 this.addLine( this.ipad + "_this = this;");
242 // for non top level = _this point to owner, and _this.ID is set
244 this.addLine( this.ipad + "_this = _owner;");
246 if (this.node.props.has_key("id")
248 this.node.xvala_id != ""
250 this.node.xvala_id[0] != '*'
252 this.node.xvala_id[0] != '+'
254 this.addLine( this.ipad + "_this." + node.xvala_id + " = this;");
262 protected void addInitMyVars()
264 //var meths = this.palete.getPropertiesFor(item['|xns'] + '.' + item.xtype, 'methods');
265 //print(JSON.stringify(meths,null,4));Seed.quit();
269 // initialize.. my vars..
271 this.addLine( this.ipad + "// my vars (dec)");
273 var iter = this.myvars.list_iterator();
279 var prop = this.node.props.get(k);
281 var v = prop.val.strip();
286 // at this point start using
288 if (v == "FALSE" || v == "TRUE") {
291 //FIXME -- check for raw string.. "string XXXX"
292 var is_raw = prop.ptype == NodePropType.RAW;
294 // what's the type.. - if it's a string.. then we quote it..
295 if (prop.rtype == "string" && !is_raw) {
296 v = "\"" + v.escape("") + "\"";
298 // if it's a string...
300 prop.start_line = this.cur_line;
301 this.addLine(this.ipad + "this." + prop.name + " = " + v +";");
302 prop.end_line = this.cur_line;
310 protected void addWrappedProperties()
312 var cls = Palete.Gir.factoryFqn((Project.Gtk) this.file.project, this.node.fqn());
314 GLib.debug("Skipping wrapped properties - could not find class %s" , this.node.fqn());
318 if (this.node.fqn() == "Gtk.NotebookPage") {
321 // what are the properties of this class???
323 this.addLine(this.ipad + "// set gobject values");
325 foreach(var p in cls.props.keys) {
326 var val = cls.props.get(p);
327 //print("Check Write %s\n", p);
328 if (!this.node.has(p)) {
331 if (this.shouldIgnoreWrapped(p)) {
338 var prop = this.node.get_prop(p);
341 // user defined properties.
342 if (prop.ptype == NodePropType.USER) {
348 var is_raw = prop.ptype == NodePropType.RAW;
350 // what's the type.. - if it's a string.. then we quote it..
351 if (val.type == "string" && !is_raw) {
352 v = "\"" + v.escape("") + "\"";
354 if (v == "TRUE" || v == "FALSE") {
357 if (val.type == "float" && v[v.length-1] != 'f') {
361 prop.start_line = this.cur_line;
362 this.addLine("%s%s%s = %s;".printf(ipad,this.this_el,p,v)); // // %s, iter.get_value().type);
366 prop.end_line = this.cur_line;
373 * pack the children into the parent.
375 * if the child's id starts with '*' then it is not packed...
376 * - this allows you to define children and add them manually..
379 protected void addChildren()
382 GLib.debug("addChildren %s, %d", this.node.fqn(), (int)this.node.readItems().size);
383 if (this.node.readItems().size < 1) {
386 this.pane_number = 0;
387 var cols = this.node.has("* columns") ? int.max(1, int.parse(this.node.get_prop("* columns").val)) : 1;
395 foreach(var child in this.node.readItems()) {
400 if (child.xvala_id[0] == '*') {
401 continue; // skip generation of children?
404 // probably added in ctor..
405 if (child.has("* prop") && this.shouldIgnoreWrapped(child.get_prop("* prop").val)) {
408 // create the element..
411 // this is only needed if it does not have an ID???
412 var childname = this.addPropSet(child, child.has("id") ? child.get_prop("id").val : "") ;
413 if (!child.has("id") && this.this_el == "this.el.") {
414 this.addLine(this.ipad + childname +".ref();");
416 if (child.has("* prop")) {
417 if (this.node.fqn() == "Gtk.NotebookPage") {
418 switch (child.get_prop("* prop").val) {
420 nb_child = childname + (this.this_el == "this.el." ? ".el" : "");
424 nb_tab = childname + (this.this_el == "this.el." ? ".el" : "");
428 nb_menu = childname + (this.this_el == "this.el." ? ".el" : "");
434 // fixme special packing!??!?!
435 if (child.get_prop("* prop").val.contains("[]")) {
436 // currently this is not used?
437 // and it will not add ref..
439 this.packChild(child, childname, 0, 0, child.get_prop("* prop").val); /// fixme - this is a bit speciall...
445 this.ignoreWrapped(child.get_prop("* prop").val);
446 var el_name = this.this_el == "this.el." ? ".el" : "";
449 this.addLine(ipad + this.this_el + child.get_prop("* prop").val + " = " + childname + el_name +";");
454 this.packChild(child, childname, cols, colpos);
456 if (child.has("colspan")) {
457 colpos += int.parse(child.get_prop("colspan").val);
463 // this.{id - without the '+'} = the element...
468 GLib.debug("got node %s with nb_child= %s", this.node.fqn() , nb_child);
469 if (this.node.fqn() == "Gtk.NotebookPage" && nb_child != "") {
470 var nb = (this.this_el == "this.el." ? "notebook.el" : "notebook");
472 if (nb_tab == "" && this.node.has("tab_label")) {
473 nb_tab = "new Gtk.Label(this.tab_label)";
476 if (nb_menu == "" && nb_tab == "") {
477 this.addLine(@"$(ipad)$(nb).append_page( $(nb_child) );");
481 this.addLine(@"$(ipad)$(nb).append_page( $(nb_child) , $(nb_tab) );");
484 this.addLine(@"$(ipad)$(nb).append_page_menu( $(nb_child) , $(nb_tab), $(nb_menu) );");
490 var childname = new Xcls_.... (....)
494 protected string addPropSet(Node child, string child_name)
499 if (child.has("* args")) {
501 var ar = child.get_prop("* args").val.split(",");
502 for (var ari = 0 ; ari < ar.length; ari++ ) {
503 var arg = ar[ari].split(" ");
504 xargs += "," + arg[arg.length -1];
508 var childname = "child_" + "%d".printf(this.child_count++);
510 if (child_name == "") {
511 prefix = "var " + childname + " = ";
513 var cls = child.xvala_xcls;
515 if (this.this_el == "this.") {
516 var clsdata = Palete.Gir.factoryFqn((Project.Gtk) this.file.project, this.node.fqn());
517 //if (clsdata.is_sealed) {
518 cls = this.node.fqn(); // need ctor data...
519 this.addLine(this.ipad + @"$(prefix)new $cls( _this $xargs);" );
520 return child_name == "" ? childname : ("_this." + child_name);
524 if (child.fqn() == "Gtk.NotebookPage") {
528 this.addLine(this.ipad + @"$(prefix)new $cls( _this $xargs);" );
530 // add a ref... (if 'id' is not set... to a '+' ?? what does that mean? - fake ids?
531 // remove '+' support as I cant remember what it does!!!
532 //if (child.xvala_id.length < 1 ) {
533 // this.addLine(this.ipad + childname +".ref();"); // we need to reference increase unnamed children...
535 //if (child.xvala_id[0] == '+') {
536 // this.addLine(this.ipad + "this." + child.xvala_id.substring(1) + " = " + childname+ ";");
541 return child_name == "" ? childname : ("_this." + child_name);
547 protected void packChild(Node child, string childname, int cols, int colpos, string propname= "")
550 GLib.debug("packChild %s=>%s", this.node.fqn(), child.fqn());
551 // forcing no packing? - true or false? -should we just accept false?
552 if (child.has("* pack") && child.get("* pack").down() == "false") {
553 return; // force no packing
555 if (child.has("* pack") && child.get("* pack").down() == "true") {
556 return; // force no packing
558 var el_name = this.this_el == "this.el." ? ".el" : "";
559 var this_el = this.this_el;
560 // BC really - don't want to support this anymore.
561 if (child.has("* pack")) {
563 string[] packing = { "add" };
564 if (child.has("* pack")) {
565 packing = child.get("* pack").split(",");
568 var pack = packing[0];
569 this.addLine(this.ipad + this.this_el + pack.strip() + " ( " + childname + el_name + " " +
570 (packing.length > 1 ?
571 (", " + string.joinv(",", packing).substring(pack.length+1))
575 var childcls = this.file.project.palete.getClass(child.fqn()); // very trusting..
576 if (childcls == null) {
580 var is_event = childcls.inherits.contains("Gtk.EventController") || childcls.implements.contains("Gtk.EventController");
582 this.addLine(this.ipad + this.this_el + "add_controller( %s.el );".printf(childname) );
587 switch (this.node.fqn()) {
593 var x = child.has("x") ? child.get_prop("x").val : "0";
594 var y = child.has("y") ? child.get_prop("y").val : "0";
595 this.addLine(@"$(ipad)$(this_el)put( $(childname)$(el_name), $(x), $(y) );");
601 var named = child.has("stack_name") ? child.get_prop("stack_name").val.escape() : "";
602 var title = child.has("stack_title") ? child.get_prop("stack_title").val.escape() : "";
603 if (title.length > 0) {
604 this.addLine(@"$(ipad)$(this_el)add_titled( $(childname)$(el_name), \"$(named)\", \"$(title)\" );");
607 this.addLine(@"$(ipad)$(this_el)add_named( $(childname)$(el_name), \"$(named)\");");
610 case "Gtk.Notebook": // use label
611 if (child.fqn() == "Gtk.NotebookPage") {
614 var label = child.has("notebook_label") ? child.get_prop("notebook_label").val.escape() : "";
615 this.addLine(@"$(ipad)$(this_el)append_page( $(childname)$(el_name), new Gtk.Label(\"$(label)\");");
620 case "Gtk.TreeView": // adding TreeViewColumns
621 this.addLine(this.ipad + "this.el.append_column( " + childname + ".el );");
624 case "Gtk.TreeViewColumn": //adding Renderers - I think these are all proprerties of the renderer used...
625 if (child.has("markup_column") && int.parse(child.get_prop("markup_column").val) > -1) {
626 var val = child.get_prop("markup_column").val;
627 this.addLine(@"$(ipad)$(this_el)add_attribute( $(childname)$(el_name), \"markup\", $(val) );");
630 if (child.has("text_column") && int.parse(child.get_prop("text_column").val) > -1) {
631 var val = child.get_prop("text_column").val;
632 this.addLine(@"$(ipad)$(this_el)add_attribute( $(childname)$(el_name), \"text\", $(val) );");
634 if (child.has("pixbuf_column") && int.parse(child.get_prop("pixbuf_column").val) > -1) {
635 var val = child.get_prop("pixbuf_column").val;
636 this.addLine(@"$(ipad)$(this_el).add_attribute( $(childname)$(el_name), \"pixbuf\", $(val) );");
638 if (child.has("pixbuf_column") && int.parse(child.get_prop("active_column").val) > -1) {
639 var val = child.get_prop("active_column").val;
640 this.addLine(@"$(ipad)$(this_el).add_attribute( $(childname)$(el_name), \"active\", $(val) );");
642 if (child.has("background_column") && int.parse(child.get_prop("background_column").val) > -1) {
643 var val = child.get_prop("background_column").val;
644 this.addLine(@"$(ipad)$(this_el).add_attribute( $(childname)$(el_name), \"background-rgba\", $(val) );");
646 this.addLine(this.ipad + "this.el.add( " + childname + ".el );");
651 if (propname == "buttons[]") {
652 var resp_id = int.parse(childname.replace("child_", ""));
653 if (child.has("* response_id")) {
654 resp_id = int.parse(child.get_prop("* response_id").val);
656 this.addLine(@"$(ipad)$(this_el).add_action_widget( $(childname)$(el_name), $(resp_id) );");
661 this.addLine(@"$(ipad)$$(this_el)get_content_area().add( $(childname)$(el_name) );");
669 // known working with GTK4 !
670 case "Gtk.HeaderBar": // it could be end... - not sure how to hanle that other than overriding this.addLine(this.ipad + "this.el.add_action_widget( %s.el, %d);".printf(childname,resp_id) ); the pack method?
671 this.addLine(@"$(ipad)$(this_el)pack_start( $(childname)$(el_name) );");
675 this.addLine(@"$(ipad)$(this_el)append_item( $(childname)$(el_name) );");
680 switch(this.pane_number) {
682 this.addLine(@"$(ipad)$(this_el)pack_start( $(childname)$(el_name) );");
685 this.addLine(@"$(ipad)$(this_el)pack_end( $(childname)$(el_name) );");
693 case "Gtk.ColumnView":
694 this.addLine(@"$(ipad)$(this_el)append_column( $(childname)$(el_name) );");
698 var x = "%d".printf(colpos % cols);
699 var y = "%d".printf(( colpos - (colpos % cols) ) / cols);
700 var w = child.has("colspan") ? child.get_prop("colspan").val : "1";
702 this.addLine(@"$(ipad)$(this_el)attach( $(childname)$(el_name), $x, $y, $w, $h );");
706 this.addLine(@"$(ipad)$(this_el)append( $(childname)$(el_name) );");
707 // gtk4 uses append!!!! - gtk3 - uses add..
716 // fixme GtkDialog?!? buttons[]
718 // fixme ... add case "Gtk.RadioButton": // group_id ??
722 protected void addInit()
726 if (!this.node.has("* init")) {
730 this.addLine(ipad + "// init method");
732 this.node.setLine(this.cur_line, "p", "init");
734 var init = this.node.get_prop("* init");
735 init.start_line = this.cur_line;
736 this.addMultiLine(ipad + this.padMultiline(ipad, init.val) );
737 init.end_line = this.cur_line;
739 protected void addListeners()
741 if (this.node.listeners.size < 1) {
746 this.addLine(ipad + "//listeners");
750 var iter = this.node.listeners.map_iterator();
751 while (iter.next()) {
752 var k = iter.get_key();
753 var prop = iter.get_value();
756 prop.start_line = this.cur_line;
757 this.node.setLine(this.cur_line, "l", k);
758 this.addMultiLine(this.ipad + this.this_el + k + ".connect( " +
759 this.padMultiline(this.ipad,v) +");");
760 prop.end_line = this.cur_line;
763 protected void addEndCtor()
767 this.addLine(this.pad + "}");
772 * Standardize this crap...
774 * standard properties (use to set)
775 * If they are long values show the dialog..
778 * bool is_xxx :: can show a pulldown.. (true/false)
780 * $ string html = string with value interpolated eg. baseURL + ".."
781 * Clutter.ActorAlign x_align (typed) -- shows pulldowns if type is ENUM?
782 * $ untypedvalue = javascript untyped value...
783 * _ string html ... = translatable..
786 * object properties (not part of the GOjbect being wrapped?
787 * # Gee.ArrayList<Xcls_fileitem> fileitems
792 * methods -- always text editor..
800 * * init -- big string?
802 * event handlers (listeners)
807 * +XXXX -- indicates it's a instance property / not glob...
808 * *XXXX -- skip writing glob property (used as classes that can be created...)
813 protected void addUserMethods()
816 this.addLine(this.pad + "// user defined functions");
818 // user defined functions...
819 var iter = this.node.props.map_iterator();
821 var prop = iter.get_value();
822 if (this.shouldIgnore(prop.name)) {
825 // HOW TO DETERIME if its a method?
826 if (prop.ptype != NodePropType.METHOD) {
827 //strbuilder("\n" + pad + "// skip " + k + " - not pipe \n");
831 // function in the format of {type} (args) { .... }
835 prop.start_line = this.cur_line;
836 this.node.setLine(this.cur_line, "p", prop.name);
837 this.addMultiLine(this.pad + "public " + prop.rtype + " " + prop.name + " " + this.padMultiline(this.pad, prop.val));;
838 prop.end_line = this.cur_line;
843 protected void iterChildren()
845 this.node.line_end = this.cur_line;
846 this.node.sortLines();
849 if (this.depth > 0) {
850 this.addLine(this.inpad + "}");
853 var iter = this.node.readItems().list_iterator();
855 while (iter.next()) {
856 this.addMultiLine(this.mungeChild(iter.get()));
859 if (this.depth < 1) {
860 this.addLine(this.inpad + "}");
867 protected void ignoreWrapped(string i) {
868 this.ignoreWrappedList.add(i);
872 protected bool shouldIgnoreWrapped(string i)
874 return ignoreWrappedList.contains(i);