resources/RooUsage.txt
[app.Builder.js] / src / JsRender / NodeToGtk.vala
1 /*
2
3 * This code renders the Gtk tree into a set of Gtk elements.
4 * principle = one NodeToGtk wraps around the original 'node'
5 *  
6 * it's called by the view element with
7 *       var x = new JsRender.NodeToGtk(file.tree);
8      var obj = x.munge() as Gtk.Widget;
9        
10 *
11
12 * The idea behind the Javascript tools stuff is that we can 
13 * transform what is actually being requested to be rendered
14 * -- eg. an AboutBox, and turn that into load of real widgets..
15 * that could be displayed..
16
17 * we could go on the theory that we send the whole tree to the 'plugin'
18 * and that would do all the transformations before rendering..
19 * -- this would make more sense...
20 * -- otherwise we would call it on each element, and might get really confused
21 * about scope etc..
22
23
24
25 */
26 public class JsRender.NodeToGtk : Object {
27
28         Node node;
29         Object wrapped_object; 
30         NodeToGtk parentObj;
31         
32         Gee.ArrayList<NodeToGtk> children;
33         
34         Gee.ArrayList<string> els;
35         //Gee.ArrayList<string> skip;
36         Gee.HashMap<string,string> ar_props;
37         public static int vcnt = 0; 
38
39         public NodeToGtk( Node node , NodeToGtk? parent_obj = null) 
40         {
41                 this.node = node;
42                 this.els = new Gee.ArrayList<string>(); 
43                 this.children = new Gee.ArrayList<NodeToGtk>(); 
44                 //this.skip = new Gee.ArrayList<string>();
45                 this.ar_props = new Gee.HashMap<string,string>();
46                 this.parentObj = parent_obj;
47                 
48                 if (parent_obj == null) {
49                         // then serialize up the node,
50                         // send it to javascript for processsing,
51                         // then rebuild node from return value..
52                         try {
53                                 var ret = Palete.Javascript.singleton().executeFile(
54                                                 BuilderApplication.configDirectory() + "/resources/node_to_gtk.js",
55                                                 "node_to_gtk",
56                                                 node.toJsonString()
57                                 );
58                                 var new_node = new Node();
59                                 var pa = new Json.Parser();
60                                 pa.load_from_data(ret);
61                                 var rnode = pa.get_root();
62                            
63                                 
64                                 new_node.loadFromJson(rnode.get_object(), 2);
65                                 this.node = new_node;
66                                 
67                         } catch (Palete.JavascriptError e) {
68                                 print("Error: %s\n", e.message);
69                         }
70                         
71                         
72                 }
73                 
74         }
75         
76         public Object? munge ( )
77         {
78                 var ret = this.mungeNode();
79                 if (ret == null) {
80                         return null;
81                 }
82                         
83                 return ret.wrapped_object;
84                       
85         }
86         public NodeToGtk? mungeChild(  Node cnode)
87         {
88                 var x = new  NodeToGtk(cnode, this);
89                 
90                 return x.mungeNode();
91                 
92         }
93         
94         public NodeToGtk? mungeNode()
95         {
96                 
97                 var parent = this.parentObj != null ? this.parentObj.wrapped_object : null;
98                 var cls = this.node.fqn().replace(".", "");
99                 var ns = this.node.fqn().split(".")[0];
100                 var gtkbuilder = new global::Gtk.Builder();
101
102                 var cls_gtype = gtkbuilder.get_type_from_name(cls);
103                 print("Type: %s ?= %s\n", this.node.fqn(), cls_gtype.name());
104
105                 if (cls_gtype == GLib.Type.INVALID) {
106                         print("SKIP - gtype is invalid\n");
107                         return null;
108                 }
109                 // if it's a window...  -- things we can not render....
110
111                 if (cls_gtype.is_a(typeof(global::Gtk.Window))) {
112                         // what if it has none...
113                         if (this.node.items.size < 1) {
114                                 return null;
115                         }
116                         return this.mungeChild(this.node.items.get(0));
117                 }
118                 if (cls_gtype.is_a(typeof(global::Gtk.Popover))) {
119                         // what if it has none...
120                         if (this.node.items.size < 1) {
121                                 return null;
122                         }
123                         return this.mungeChild(this.node.items.get(0));
124                 }
125
126                 var ret = Object.new(cls_gtype);
127                 ret.ref(); //??? problematic?
128                 this.wrapped_object = ret;
129                 
130                  
131                 switch(cls) {
132                         // fixme
133                         //case "GtkTreeStore": // top level.. - named and referenced
134                         case "GtkListStore": // top level.. - named and referenced
135                         //case "GtkTreeViewColumn": // part of liststore?!?!
136                         //case "GtkMenu": // top level..
137                         //case "GtkCellRendererText":
138                         case "GtkSourceBuffer":                         
139                         case "GtkClutterActor"://fixme..
140                         case "GtkClutterEmbed"://fixme.. -- we can not nest embedded.. need to solve..
141                                         
142                                 return null;
143                 }
144
145                 this.packParent();
146                 
147
148                 // pack paramenters
149
150                 
151                 if (parent != null && parent.get_type().is_a(typeof(global::Gtk.Container))) {
152                         this.packContainerParams();
153                 }
154                 
155                 var cls_gir =Palete.Gir.factoryFqn(this.node.fqn()); 
156                 if (cls_gir == null) {
157                         return null;
158                 }
159                 //var id = this.node.uid();
160                 //var ret = @"$pad<object class=\"$cls\" id=\"$id\">\n";
161                 // properties..
162                 var props = cls_gir.props;
163                 
164               
165                 var pviter = props.map_iterator();
166                 while (pviter.next()) {
167                         
168                                 // print("Check: " +cls + "::(" + pviter.get_value().propertyof + ")" + pviter.get_key() + " " );
169                         var k = pviter.get_key();
170                         // skip items we have already handled..
171                         if  (!this.node.has(k)) {
172                                 continue;
173                         }
174                         // find out the type of the property...
175                         var type = pviter.get_value().type;
176                         type = Palete.Gir.fqtypeLookup(type, ns);
177
178                         var  ocl = (ObjectClass) cls_gtype.class_ref ();
179                         var ps = ocl.find_property(k);
180                         
181                         // attempt to read property type and enum...
182                         
183                         if (ps != null) {
184                                 var vt = ps.value_type;
185                                 if (vt.is_enum()) {
186                                         
187                                         var raw_val = this.node.get(k).strip();
188                                         var rv_s = raw_val.split(".");
189                                         if (rv_s.length > 0) {
190                                                 raw_val = rv_s[rv_s.length-1];                                  
191                                                 EnumClass ec = (EnumClass) vt.class_ref ();
192                                                 var foundit = false;
193                                                 for (var i =0;i< ec.n_values; i++) {
194                                                         var ev = ec.values[i].value_name;
195                                                         var ev_s= ev.split("_");
196                                                         if (raw_val == ev_s[ev_s.length-1]) {
197                                                                 var sval = GLib.Value(typeof(int));
198                                                                 sval.set_int(ec.values[i].value);
199                                                                 ret.set_property(k, sval);
200                                                                 foundit = true;
201                                                                 break;
202                                                         }
203                                                 }
204                                                 if (foundit) {
205                                                         continue;
206                                                 }
207                                                         
208                                         }
209                                 }
210                         }
211
212
213                         
214
215                         var val = this.toValue(this.node.get(k).strip(), type);
216                         if (val == null) {
217                                 print("skip (failed to transform value %s type = %s from %s\n", 
218                                         cls + "." + k, type,  this.node.get(k).strip());
219                                 continue;
220                         }
221                         print ("set_property ( %s , %s / %s)\n", k, this.node.get(k).strip(), val.strdup_contents());
222                         
223                         
224                         ret.set_property(k, val);  
225                         
226
227                 }
228                 // packing???
229                 // for now... - just try the builder style packing
230                 
231                 
232                  
233                 if (this.node.items.size < 1) {
234                         return this;
235                 }
236                 
237                 for (var i = 0; i < this.node.items.size; i++ ) {
238
239                          var ch = this.mungeChild(this.node.items.get(i));
240                          if (ch != null) {
241                                  this.children.add(ch);
242                          }
243                          
244                 }
245                 
246                 this.afterChildren();
247                 
248                 return this;
249                 
250
251                  
252
253         }
254         
255         public void  afterChildren()
256         {
257                 // things like GtkNotebook - we have to pack children after they have been created..
258                 var cls = this.node.fqn().replace(".", "");
259                 
260                 if (cls == "GtkNotebook") {
261                         this.afterChildrenGtkNotebook();
262                 }
263                 
264                 
265                 
266         }
267         
268         public void  afterChildrenGtkNotebook()
269         {
270                 // we have a number of children..
271                 // some are labels - this might need to be more complex...
272                 // perhaps labels should be a special property labels[] of the notebook..
273                 var labels = new Gee.ArrayList<NodeToGtk>();
274                 var bodies = new Gee.ArrayList<NodeToGtk>();
275                 for (var i = 0; i < this.children.size; i++) { 
276                         var cn = this.children.get(i).node.fqn().replace(".", "");
277                         if (cn != "GtkLabel") {
278                                 bodies.add(this.children.get(i));
279                                 continue;
280                         }
281                         labels.add(this.children.get(i));
282                 }
283                 for (var i = 0; i < bodies.size; i++) {
284                         var lbl = (i > (labels.size -1)) ? null : labels.get(i);
285
286                         ((global::Gtk.Notebook)this.wrapped_object).append_page(
287                                  (global::Gtk.Notebook) bodies.get(i).wrapped_object,
288                                  lbl != null ?  (global::Gtk.Notebook) lbl.wrapped_object : null
289                         );
290                         
291                         
292                 }
293                 
294                 
295         }
296         
297         
298         /**
299          * called after the this.object  has been created
300          * and it needs to be packed onto parent.
301          */
302         public void packParent() 
303         {
304                 var cls = this.node.fqn().replace(".", "");
305                 
306                 var gtkbuilder = new global::Gtk.Builder();
307                 var cls_gtype = gtkbuilder.get_type_from_name(cls);
308
309                 if (this.parentObj == null) {
310                         return;
311                 }
312                                 
313                     
314                 var parent = this.parentObj.wrapped_object;
315                 
316                 var do_pack =true;
317
318                 if (parent == null) { // no parent.. can not pack.
319                         return; /// 
320                 }
321                 // -------------  handle various special parents .. -----------
322                 
323                 var par_type = this.parentObj.node.fqn().replace(".", "");
324                 
325                 if (par_type == "GtkNotebook") {
326                         // do not pack - it's done afterwards...
327                         return;
328                 }
329                 
330                 // -------------  handle various child types.. -----------
331                 // our overrides
332                 if (cls == "GtkMenu") {
333                         this.packMenu();
334                         return;
335                 }
336
337                 if (cls == "GtkTreeStore") { // other stores?
338                         // tree store is buildable??? --- 
339                         this.packTreeStore();
340                         return;
341                 }
342                 if (cls =="GtkTreeViewColumn") { // other stores?
343                         //?? treeview column is actually buildable -- but we do not use the builder???
344                         this.packTreeViewColumn();
345                         return;
346                 }
347                 if (cls_gtype.is_a(typeof(global::Gtk.CellRenderer))) { // other stores?
348                         this.packCellRenderer();
349                         return;
350                 }
351
352
353                 
354                 // -- handle buildable add_child..
355                 if (    cls_gtype.is_a(typeof(global::Gtk.Buildable))
356                      && 
357                         parent.get_type().is_a(typeof(global::Gtk.Buildable))
358                 )
359                 {
360                         ((global::Gtk.Buildable)parent).add_child(gtkbuilder, 
361                                                   this.wrapped_object, null);
362                         return;
363                 }
364                 // other packing?
365
366                 
367
368         }
369
370         public void packMenu()
371         {
372
373
374                 var parent = this.parentObj.wrapped_object;
375                 if (!parent.get_type().is_a(typeof(global::Gtk.Widget))) {
376                         print("skip menu pack - parent is not a widget");
377                         return;
378                 }
379                 
380                 var p = (global::Gtk.Menu)this.wrapped_object;
381                 ((global::Gtk.Widget)parent).button_press_event.connect((s, ev) => { 
382                         p.set_screen(Gdk.Screen.get_default());
383                         p.show_all();
384                         p.popup(null, null, null, ev.button, ev.time);
385                         return true;
386                 });
387         }
388
389         public void packTreeStore()
390         {
391                 var parent = this.parentObj.wrapped_object;
392                 if (!parent.get_type().is_a(typeof(global::Gtk.TreeView))) {
393                         print("skip treestore pack - parent is not a treeview");
394                         return;
395                 }
396                 ((global::Gtk.TreeView)parent).set_model((global::Gtk.TreeModel)this.wrapped_object);
397                 
398         }
399         public void packTreeViewColumn()
400         {
401                 var parent = this.parentObj.wrapped_object;
402                 if (!parent.get_type().is_a(typeof(global::Gtk.TreeView))) {
403                         print("skip packGtkViewColumn pack - parent is not a treeview");
404                         return;
405                 }
406                 ((global::Gtk.TreeView)parent).append_column((global::Gtk.TreeViewColumn)this.wrapped_object);
407                 // init contains the add_attribute for what to render...
408                 
409         }       
410
411
412         public void packCellRenderer()
413         {
414                 var parent = this.parentObj.wrapped_object;
415                 if (!parent.get_type().is_a(typeof(global::Gtk.TreeViewColumn))) {
416                         print("skip packGtkViewColumn pack - parent is not a treeview");
417                         return;
418                 }
419                 ((global::Gtk.TreeViewColumn)parent).pack_start((global::Gtk.CellRenderer)this.wrapped_object, false);
420                 // init contains the add_attribute for what to render...
421                 
422         }       
423
424
425         public void packContainerParams()
426         {
427          
428                 if (this.parentObj == null) {
429                         return;
430                 }
431                 // child must be a widget..
432                 if (!this.wrapped_object.get_type().is_a(typeof(global::Gtk.Widget))) {
433                         return;
434                 }
435                 
436                 var parent_gir = Palete.Gir.factoryFqn(this.parentObj.node.fqn());
437
438                 var parent = this.parentObj.wrapped_object;
439                 
440                 if (parent_gir == null) {
441                         return;
442                 }
443                 
444                 // let's test just setting expand to false...
445                 var cls_methods = parent_gir.methods;
446                 if (cls_methods == null) {
447                         return;
448                 }
449         
450                 if (!this.node.props.has_key("* pack") || 
451                                 this.node.props.get("* pack").length < 1) {
452                         return;
453                 }
454                 
455                 var ns = this.parentObj.node.fqn().split(".")[0];
456                  
457                 var pack = this.node.props.get("* pack").split(",");
458                 
459                 // this tries to use the parameter names from the '*pack' function as properties in child_set_property.
460             // for a grid it's trying to do left/top/width/height.
461             
462             
463                 if (cls_methods.has_key(pack[0])) {
464                         var mparams = cls_methods.get(pack[0]).paramset.params;
465                         for (var i = 1; i < mparams.size; i++ ) {
466                                 if (i > (pack.length -1)) {
467                                         continue;
468                                 }
469                                 Palete.Gir.checkParamOverride(mparams.get(i));
470                                 var k = mparams.get(i).name;
471
472                                 Value cur_val;
473                                  
474                                 var type = mparams.get(i).type;
475                                 type = Palete.Gir.fqtypeLookup(type, ns);
476
477                                 var val = this.toValue(pack[i].strip(), type);
478                                 if (val == null) {
479                                         print("skip (failed to transform value %s type = %s from %s\n", 
480                                                 this.parentObj.node.fqn()  + "." + k, type, pack[i].strip());
481                                         continue;
482                                 }
483                                 print ("pack:set_property ( %s , %s / %s)\n", k, pack[i].strip(), val.strdup_contents());
484         
485                                 ((global::Gtk.Container)parent).child_set_property(
486                                         (global::Gtk.Widget)this.wrapped_object , k, val);
487                                  
488                         }
489                 
490                 }
491         
492
493
494                         
495         }
496                    
497
498         public GLib.Value? toValue(string val, string type) {
499
500                 
501                 /*
502                 if (type == "string") {
503                         var qret = GLib.Value(typeof(string));
504                         qret.set_string(val);
505                         return qret;
506                 }
507                 * */
508                 /*
509                  * 
510            * var gtkbuilder = new global::Gtk.Builder();
511                 var prop_gtype = gtkbuilder.get_type_from_name(type);
512                 
513
514                 if (prop_gtype == GLib.Type.INVALID) {
515                          
516                         return null;
517                 }
518                 */
519                 
520                  
521
522
523                 switch(type) {
524                         case "bool":
525                                 var ret = GLib.Value(typeof(bool));
526                                 ret.set_boolean(val.down() == "false" ? false : true);
527                                 return ret;
528                                 
529                         case "uint":
530                                 var ret = GLib.Value(typeof(uint));
531                                 ret.set_uint(int.parse(val));
532                                 return ret;
533                                 
534                         case "int":
535                                 var ret = GLib.Value(typeof(int));
536                                 ret.set_int(int.parse(val));
537                                 return ret;
538
539                         // uint64 ...??
540
541                         case "long":
542                                 var ret = GLib.Value(typeof(long));
543                                 ret.set_long((long)int64.parse(val));
544                                 return ret;
545                         
546                         case "ulong":
547                                 var ret = GLib.Value(typeof(ulong));
548                                 ret.set_ulong((ulong) uint64.parse(val));
549                                 return ret;
550
551                         case "float":
552                                 var ret = GLib.Value(typeof(float));
553                                 ret.set_float((float)double.parse(val));
554                                 return ret;
555                                 
556                         case "string":
557                                 var ret = GLib.Value(typeof(string));
558                                 ret.set_string(val);
559                                 return ret;
560
561                         default:
562                                 return null;
563                                 /*
564                                 var sval =  GLib.Value(typeof(string));
565                                 sval.set_string(val);
566                         
567                                 if (!sval.transform(ref ret)) {
568                                 
569                                         return null;
570                                 }
571                                 return ret;
572                                 */
573                 }
574                 // should not get here..
575                 return null;
576         }
577         
578          
579           
580                 
581 }