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