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