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