src/JsRender/NodeToGtk.vala
[app.Builder.js] / src / JsRender / NodeToGtk.vala
1 /*
2
3  
4 */
5 public class JsRender.NodeToGtk : Object {
6
7         Node node;
8         Object wrapped_object; 
9         NodeToGtk parentObj;
10         
11         Gee.ArrayList<NodeToGtk> children;
12         
13         Gee.ArrayList<string> els;
14         //Gee.ArrayList<string> skip;
15         Gee.HashMap<string,string> ar_props;
16         public static int vcnt = 0; 
17
18         public NodeToGtk( Node node) 
19         {
20                 this.node = node;
21                 this.els = new Gee.ArrayList<string>(); 
22                 this.children = new Gee.ArrayList<NodeToGtk>(); 
23                 //this.skip = new Gee.ArrayList<string>();
24                 this.ar_props = new Gee.HashMap<string,string>();
25                 this.parentObj = null;
26         }
27         
28         public Object? munge ( )
29         {
30                 var ret = this.mungeNode();
31                 if (ret == null) {
32                         return null;
33                 }
34                         
35                 return ret.wrapped_object;
36                       
37         }
38         public NodeToGtk? mungeChild(  Node cnode)
39         {
40                 var x = new  NodeToGtk(cnode);
41                 x.parentObj = this;
42                 return x.mungeNode();
43                 
44         }
45         
46         public NodeToGtk? mungeNode()
47         {
48
49                 var parent = this.parentObj != null ? this.parentObj.wrapped_object : null;
50                 var cls = this.node.fqn().replace(".", "");
51                 var ns = this.node.fqn().split(".")[0];
52                 var gtkbuilder = new global::Gtk.Builder();
53
54                 var cls_gtype = gtkbuilder.get_type_from_name(cls);
55                 print("Type: %s ?= %s\n", this.node.fqn(), cls_gtype.name());
56
57                 if (cls_gtype == GLib.Type.INVALID) {
58                         print("SKIP - gtype is invalid\n");
59                         return null;
60                 }
61                 // if it's a window... 
62
63                 if (cls_gtype.is_a(typeof(global::Gtk.Window))) {
64                         // what if it has none...
65                         if (this.node.items.size < 1) {
66                                 return null;
67                         }
68                         return this.mungeChild(this.node.items.get(0));
69                 }
70
71                 var ret = Object.new(cls_gtype);
72                 ret.ref(); //??? problematic?
73                 this.wrapped_object = ret;
74                 
75                  
76                 switch(cls) {
77                         // fixme
78                         //case "GtkTreeStore": // top level.. - named and referenced
79                         case "GtkListStore": // top level.. - named and referenced
80                         //case "GtkTreeViewColumn": // part of liststore?!?!
81                         //case "GtkMenu": // top level..
82                         //case "GtkCellRendererText":
83                         case "GtkSourceBuffer":                         
84                         case "GtkClutterActor"://fixme..
85                         case "GtkClutterEmbed"://fixme.. -- we can not nest embedded.. need to solve..
86                                         
87                                 return null;
88                 }
89
90                 this.packParent();
91                 
92
93                 // pack paramenters
94
95                 
96                 if (parent != null && parent.get_type().is_a(typeof(global::Gtk.Container))) {
97                         this.packContainerParams();
98                 }
99                 
100                 var cls_gir =Palete.Gir.factoryFqn(this.node.fqn()); 
101                 if (cls_gir == null) {
102                         return null;
103                 }
104                 //var id = this.node.uid();
105                 //var ret = @"$pad<object class=\"$cls\" id=\"$id\">\n";
106                 // properties..
107                 var props = cls_gir.props;
108                 
109               
110                 var pviter = props.map_iterator();
111                 while (pviter.next()) {
112                         
113                                 // print("Check: " +cls + "::(" + pviter.get_value().propertyof + ")" + pviter.get_key() + " " );
114                         var k = pviter.get_key();
115                         // skip items we have already handled..
116                         if  (!this.node.has(k)) {
117                                 continue;
118                         }
119                         // find out the type of the property...
120                         var type = pviter.get_value().type;
121                         type = Palete.Gir.fqtypeLookup(type, ns);
122
123                         var val = this.toValue(this.node.get(k).strip(), type);
124                         if (val == null) {
125                                 print("skip (failed to transform value %s type = %s from %s\n", 
126                                         cls + "." + k, type,  this.node.get(k).strip());
127                                 continue;
128                         }
129                         print ("set_property ( %s , %s / %s)\n", k, this.node.get(k).strip(), val.strdup_contents());
130                         
131                         
132                         ret.set_property(k, val);  
133                         
134
135                 }
136                 // packing???
137                 // for now... - just try the builder style packing
138                 
139                 
140                  
141                 if (this.node.items.size < 1) {
142                         return this;
143                 }
144                 
145                 for (var i = 0; i < this.node.items.size; i++ ) {
146
147                          var ch = this.mungeChild(this.node.items.get(i));
148                          if (ch != null) {
149                                  this.children.add(ch);
150                          }
151                          
152                 }
153                 
154                 this.afterChildren();
155                 
156                 return this;
157                 
158
159                  
160
161         }
162         
163         public void  afterChildren()
164         {
165                 // things like GtkNotebook - we have to pack children after they have been created..
166                 var cls = this.node.fqn().replace(".", "");
167                 
168                 if (cls == "GtkNotebook") {
169                         this.afterChildrenGtkNotebook();
170                 }
171                 
172                 
173                 
174         }
175         
176         public void  afterChildrenGtkNotebook()
177         {
178                 // we have a number of children..
179                 // some are labels - this might need to be more complex...
180                 // perhaps labels should be a special property labels[] of the notebook..
181                 var labels = new Gee.ArrayList<NodeToGtk>();
182                 var bodies = new Gee.ArrayList<NodeToGtk>();
183                 for (var i = 0; i < this.children.size; i++) { 
184                         var cn = this.children.get(i).node.fqn().replace(".", "");
185                         if (cn != "GtkLabel") {
186                                 bodies.add(this.children.get(i));
187                                 continue;
188                         }
189                         labels.add(this.children.get(i));
190                 }
191                 for (var i = 0; i < bodies.size; i++) { 
192                         ((global::Gtk.Notebook)this.wrapped_object).append_page(
193                                  (global::Gtk.Notebook) bodies.get(i).wrapped_object,
194                                  (labels.size > i - 1) ? 
195                                         (global::Gtk.Notebook) labels.get(i).wrapped_object :
196                                         null
197                                         
198                         );
199                         
200                         
201                 }
202                 
203                 
204         }
205         
206         
207         /**
208          * called after the this.object  has been created
209          * and it needs to be packed onto parent.
210          */
211         public void packParent() 
212         {
213                 var cls = this.node.fqn().replace(".", "");
214                 
215                 var gtkbuilder = new global::Gtk.Builder();
216                 var cls_gtype = gtkbuilder.get_type_from_name(cls);
217
218                 if (this.parentObj == null) {
219                         return;
220                 }
221                                 
222                     
223                 var parent = this.parentObj.wrapped_object;
224                 
225                 var do_pack =true;
226
227                 if (parent == null) { // no parent.. can not pack.
228                         return; /// 
229                 }
230                 // -------------  handle various special parents .. -----------
231                 
232                 var par_type = this.parentObj.node.fqn().replace(".", "");
233                 
234                 if (par_type == "GtkNotebook") {
235                         // do not pack - it's done afterwards...
236                         return;
237                 }
238                 
239                 // -------------  handle various child types.. -----------
240                 // our overrides
241                 if (cls == "GtkMenu") {
242                         this.packMenu();
243                         return;
244                 }
245
246                 if (cls == "GtkTreeStore") { // other stores?
247                         // tree store is buildable??? --- 
248                         this.packTreeStore();
249                         return;
250                 }
251                 if (cls =="GtkTreeViewColumn") { // other stores?
252                         //?? treeview column is actually buildable -- but we do not use the builder???
253                         this.packTreeViewColumn();
254                         return;
255                 }
256                 if (cls_gtype.is_a(typeof(global::Gtk.CellRenderer))) { // other stores?
257                         this.packCellRenderer();
258                         return;
259                 }
260
261
262                 
263                 // -- handle buildable add_child..
264                 if (    cls_gtype.is_a(typeof(global::Gtk.Buildable))
265                      && 
266                         parent.get_type().is_a(typeof(global::Gtk.Buildable))
267                 )
268                 {
269                         ((global::Gtk.Buildable)parent).add_child(gtkbuilder, 
270                                                   this.wrapped_object, null);
271                         return;
272                 }
273                 // other packing?
274
275                 
276
277         }
278
279         public void packMenu()
280         {
281
282
283                 var parent = this.parentObj.wrapped_object;
284                 if (!parent.get_type().is_a(typeof(global::Gtk.Widget))) {
285                         print("skip menu pack - parent is not a widget");
286                         return;
287                 }
288                 
289                 var p = (global::Gtk.Menu)this.wrapped_object;
290                 ((global::Gtk.Widget)parent).button_press_event.connect((s, ev) => { 
291                         p.set_screen(Gdk.Screen.get_default());
292                         p.show_all();
293                         p.popup(null, null, null, ev.button, ev.time);
294                         return true;
295                 });
296         }
297
298         public void packTreeStore()
299         {
300                 var parent = this.parentObj.wrapped_object;
301                 if (!parent.get_type().is_a(typeof(global::Gtk.TreeView))) {
302                         print("skip treestore pack - parent is not a treeview");
303                         return;
304                 }
305                 ((global::Gtk.TreeView)parent).set_model((global::Gtk.TreeModel)this.wrapped_object);
306                 
307         }
308         public void packTreeViewColumn()
309         {
310                 var parent = this.parentObj.wrapped_object;
311                 if (!parent.get_type().is_a(typeof(global::Gtk.TreeView))) {
312                         print("skip packGtkViewColumn pack - parent is not a treeview");
313                         return;
314                 }
315                 ((global::Gtk.TreeView)parent).append_column((global::Gtk.TreeViewColumn)this.wrapped_object);
316                 // init contains the add_attribute for what to render...
317                 
318         }       
319
320
321         public void packCellRenderer()
322         {
323                 var parent = this.parentObj.wrapped_object;
324                 if (!parent.get_type().is_a(typeof(global::Gtk.TreeViewColumn))) {
325                         print("skip packGtkViewColumn pack - parent is not a treeview");
326                         return;
327                 }
328                 ((global::Gtk.TreeViewColumn)parent).pack_start((global::Gtk.CellRenderer)this.wrapped_object, false);
329                 // init contains the add_attribute for what to render...
330                 
331         }       
332
333
334         public void packContainerParams()
335         {
336          
337                 if (this.parentObj == null) {
338                         return;
339                 }
340                 // child must be a widget..
341                 if (!this.wrapped_object.get_type().is_a(typeof(global::Gtk.Widget))) {
342                         return;
343                 }
344                 
345                 var parent_gir = Palete.Gir.factoryFqn(this.parentObj.node.fqn());
346
347                 var parent = this.parentObj.wrapped_object;
348                 
349                 if (parent_gir == null) {
350                         return;
351                 }
352                 
353                 // let's test just setting expand to false...
354                 var cls_methods = parent_gir.methods;
355                 if (cls_methods == null) {
356                         return;
357                 }
358         
359                 if (!this.node.props.has_key("* pack") && this.node.props.get("* pack") > 0) {
360                         return;
361                 }
362                 
363                 var ns = this.parentObj.node.fqn().split(".")[0];
364                  
365                 var pack = this.node.props.get("* pack").split(",");
366
367         
368                 if (cls_methods.has_key(pack[0])) {
369                         var mparams = cls_methods.get(pack[0]).paramset.params;
370                         for (var i = 1; i < mparams.size; i++ ) {
371                                 if (i > (pack.length -1)) {
372                                         continue;
373                                 }
374                         
375                                 var k = mparams.get(i).name;
376
377                                 Value cur_val;
378                                  
379                                 var type = mparams.get(i).type;
380                                 type = Palete.Gir.fqtypeLookup(type, ns);
381
382                                 var val = this.toValue(pack[i].strip(), type);
383                                 if (val == null) {
384                                         print("skip (failed to transform value %s type = %s from %s\n", 
385                                                 this.parentObj.node.fqn()  + "." + k, type, pack[i].strip());
386                                         continue;
387                                 }
388                                 print ("pack:set_property ( %s , %s / %s)\n", k, pack[i].strip(), val.strdup_contents());
389         
390                                 ((global::Gtk.Container)parent).child_set_property(
391                                         (global::Gtk.Widget)this.wrapped_object , k, val);
392                                  
393                         }
394                 
395                 }
396         
397
398
399                         
400         }
401                    
402
403         public GLib.Value? toValue(string val, string type) {
404
405                 var gtkbuilder = new global::Gtk.Builder();
406
407                 if (type == "utf8") {
408                         var qret = GLib.Value(typeof(string));
409                         qret.set_string(val);
410                         return qret;
411                 }
412                 
413                 var prop_gtype = gtkbuilder.get_type_from_name(type);
414                 
415
416                 if (prop_gtype == GLib.Type.INVALID) {
417                          
418                         return null;
419                 }
420                 
421                 
422                 var ret = GLib.Value(prop_gtype);
423
424
425                 switch(type) {
426                         case "gboolean":
427                                 ret.set_boolean(val.down() == "false" ? false : true);
428                                 return ret;
429                         case "guint":
430                                 ret.set_uint(int.parse(val));
431                                 return ret;
432                                 
433                         case "gint":
434                                 ret.set_int(int.parse(val));
435                                 return ret;
436
437                         case "gfloat":
438                                 ret.set_float(long.parse(val));
439                                 return ret;
440                                 
441                         case "utf8":
442                                 ret.set_string(val);
443                                 return ret;
444
445                         default:
446
447                                 var sval =  GLib.Value(typeof(string));
448                                 sval.set_string(val);
449                         
450                                 if (!sval.transform(ref ret)) {
451                                 
452                                         return null;
453                                 }
454                                 return ret;
455                 }
456         }
457         
458          
459           
460                 
461 }