check writable and ctor when listing properties of objects
[roobuilder] / src / Palete / Gtk.vala
1 using Gtk;
2
3
4 /**
5
6 This basically provides all the data needed to add stuff to gtk objects 
7   
8
9 */
10
11
12
13 namespace Palete {
14
15         
16         
17         
18         
19          
20
21         public class Gtk : Palete {
22                 
23                 public Gee.ArrayList<string> package_cache;
24                 
25                 public Gtk(Project.Project project)
26                 {
27
28                     aconstruct(project);
29                     this.name = "Gtk";
30                     var context = new Vala.CodeContext ();
31                          
32                     this.package_cache = this.loadPackages(Path.get_dirname (context.get_vapi_path("glib-2.0")));
33                     this.package_cache.add_all(
34                             this.loadPackages(Path.get_dirname (context.get_vapi_path("gee-0.8")))
35                     );
36                      
37                    
38                     
39                 }
40                 
41                 
42         // a) build a list of all widgets that can be added generically.
43                 // b) build child list for all containers.
44                 // c) build child list for all widgets (based on properties)
45                 // d) handle oddities?
46                 
47                 public bool loaded = false; // set to false to force a reload
48
49                 public override void  load () 
50                 {
51                         if (this.loaded) {
52                                 return;
53                         }
54                         Gir.factory(this.project, "Gtk"); // triggers a load...
55                          
56                         this.init_node_defaults();
57                         this.add_node_default_from_ctor_all();
58                     this.init_child_defaults();  
59                     
60                     this.loaded = true;
61                          
62                         
63                 }
64                 
65                 
66                 
67           
68                 
69                 public string doc(string what) 
70                 {
71                 var ns = what.split(".")[0];
72                 var gir =  Gir.factory(this.project,ns);
73                         return  ((Gir) gir).doc(what);
74                         
75                     //return typeof(this.comments[ns][what]) == 'undefined' ?  '' : this.comments[ns][what];
76                 }
77
78                         // does not handle implements...
79                 public override GirObject? getClass(string ename)
80                 {
81
82                         var es = ename.split(".");
83                         if (es.length < 2) {
84                                 return null;
85                         }
86                         var gir = Gir.factory(this.project,es[0]);
87                         if (gir == null) {
88                                 return null;
89                         }
90                         return gir.classes.get(es[1]);
91                 
92                 }
93                 
94                 public  GirObject? getDelegate(string ename) 
95                 {
96                         var es = ename.split(".");
97                         if (es.length < 2) {
98                                 return null;
99                         }
100                         var gir = Gir.factory(this.project,es[0]);
101                         if (gir == null) {
102                                 return null;
103                         }
104                         return gir.delegates.get(es[1]);
105                 
106                 }
107
108                 public  GirObject? getClassOrEnum(string ename)
109                 {
110
111                         var es = ename.split(".");
112                         if (es.length < 2) {
113                                 return null;
114                         }
115                         var gir = Gir.factory(this.project,es[0]);
116                         if (gir.classes.has_key(es[1])) {
117                                 return gir.classes.get(es[1]);
118                         }
119                         if (gir.consts.has_key(es[1])) {
120                                 return  gir.consts.get(es[1]);
121                         }
122                         return null;
123                 }
124
125
126                 public override Gee.HashMap<string,GirObject> getPropertiesFor( string ename, JsRender.NodePropType ptype) 
127                 {
128                         //print("Loading for " + ename);
129                     
130
131                         this.load();
132                                 // if (typeof(this.proplist[ename]) != 'undefined') {
133                         //print("using cache");
134                         //   return this.proplist[ename][type];
135                         //}
136                         // use introspection to get lists..
137          
138                         var es = ename.split(".");
139                         var gir = Gir.factory(this.project,es[0]);
140                         if (gir == null) {
141                                 print("WARNING = could not load vapi for %s  (%s)\n", ename , es[0]);
142                                 return new Gee.HashMap<string,GirObject>();
143                         }
144                         var cls = gir.classes.get(es[1]);
145                         if (cls == null) {
146                                 var ret = new Gee.HashMap<string,GirObject>();
147                                 return ret;
148                                 //throw new Error.INVALID_VALUE( "Could not find class: " + ename);
149                         
150                         }
151
152                         //cls.parseProps();
153                         //cls.parseSignals(); // ?? needed for add handler..
154                         //cls.parseMethods(); // ?? needed for ??..
155                         //cls.parseConstructors(); // ?? needed for ??..
156
157                         cls.overlayParent(this.project);
158
159                         switch  (ptype) {
160                                 case JsRender.NodePropType.PROP:
161                                         var ret =  this.filterProps(cls.props);
162                                         // add ctor
163                                         this.add_props_from_ctors(cls, ret);
164                                         return ret;
165                                 case JsRender.NodePropType.LISTENER:
166                                         return this.filterSignals(cls.signals);
167                                 case JsRender.NodePropType.METHOD:
168                                         return cls.methods;
169                                 case JsRender.NodePropType.CTOR:  // needed to query the arguments of a ctor.
170                                         return cls.ctors;
171                                 default:
172                                         GLib.error( "getPropertiesFor called with: " + ptype.to_string());
173                                         //var ret = new Gee.HashMap<string,GirObject>();
174                                         //return ret;
175                                 
176                         }
177                                 
178                         
179                         //cls.overlayInterfaces(gir);
180                      
181                      
182                 }
183                 // get rid of objecst from props list..
184                 public Gee.HashMap<string,GirObject>  filterProps(Gee.HashMap<string,GirObject> props)
185                 {
186                         // we shold probably cache this??
187                         
188                         var outprops = new Gee.HashMap<string,GirObject>(); 
189                         
190                         foreach(var k in props.keys) {
191                                 var val = props.get(k);
192 //                              GLib.debug("FilterProp: %s", k);
193                                 // properties that dont make any sense to display.
194                                 if (
195                                         k == "___" ||
196                                         k == "parent" ||
197                                         k == "default_widget" ||
198                                         k == "root" ||
199                                         k == "layout_manager" || // ??
200                                         k == "widget"  // gestures..
201                                 ) {
202                                         continue;
203                                 }
204                                 
205                                 if (val.is_deprecated) {
206                                         continue;
207                                 }
208                                 if (!val.is_writable && !val.ctor_only ) { // if it's ctor we accept it.
209                                         continue;
210                                 }
211                                 
212                                 if (val.type == "GLib.Object") { /// this is practually everything? ?? shoud we display it as a property?
213                                         continue;
214                                 }
215                                 if (!val.type.contains(".")) {
216                                         outprops.set(k,val);
217                                         continue;
218                                 }
219                                 var cls = this.getClassOrEnum(val.type);
220                                 
221                                 // if cls == null - it's probably a struct? I don't think we handle thses
222                                 if ( cls != null ) { // cls.nodetype == "Enum") {
223                                         // assume it's ok
224                                         outprops.set(k,val);
225                                         continue;
226                                 }
227                                 // do nothing? - classes not allowed?
228                                 
229                         }
230                         
231                         
232                         return outprops;
233                 
234                 
235                 }
236                 
237                 private void add_props_from_ctors(GirObject cls, Gee.HashMap<string,GirObject> props)
238                 {
239                         if (cls.ctors.has_key("new")) {
240                                 this.add_props_from_ctor(cls.ctors.get("new"), props);  
241                                 return;
242                         }
243                         // does not have new ?? needed?
244                         foreach(var ctor in cls.ctors.values) {
245                                 this.add_props_from_ctor(ctor, props);
246                                 break;
247                         
248                         }
249                 }
250                 
251                 private void add_props_from_ctor(GirObject ctor,  Gee.HashMap<string,GirObject> props)
252                 {
253                         var cname = ctor.gparent.fqn();
254                         GLib.debug("Add node from ctor %s:%s", ctor.gparent.fqn(), ctor.name);
255                          
256                         if (ctor.paramset == null) {
257                                 return;
258                         }
259                         
260                          
261                         // assume we are calling this for a reason...
262                         // get the first value params.
263                          
264                                 //gtk box failing
265                         //GLib.debug("No. of parmas %s %d", cls, ctor.params.size);
266                           
267                     foreach (var prop in ctor.paramset.params) {
268  
269                             
270                             if (props.has_key(prop.name)) { // overlap (we assume it's the same..)
271                                 continue;
272                         }
273                         prop.propertyof = cname + "." + ctor.name; // as it's probably not filled in..
274                             
275                             GLib.debug("adding proprty from ctor : %s, %s, %s", cname , prop.name, prop.type);
276
277                              props.set(prop.name, prop);
278                     
279                             
280                              
281                     }
282                 }
283                 
284                 
285                 
286                                 // get rid of depricated from signal list..
287                 public Gee.HashMap<string,GirObject>  filterSignals(Gee.HashMap<string,GirObject> props)
288                 {
289                         // we shold probably cache this??
290                         
291                         var outprops = new Gee.HashMap<string,GirObject>(); 
292                         
293                         foreach(var k in props.keys) {
294                                 var val = props.get(k);
295                                  
296                                 if (val.is_deprecated) {
297                                         continue;
298                                 }
299                                 
300                                 outprops.set(k,val);
301                                         
302                                 // do nothing? - classes not allowed?
303                                 
304                         }
305                         
306                         
307                         return outprops;
308                 
309                 
310                 }
311                 
312                 public string[] getInheritsFor(string ename)
313                 {
314                         string[] ret = {};
315                          
316                         var cls = this.getClass(ename);
317                          
318                         if (cls == null || cls.nodetype != "Class") {
319                                 print("getInheritsFor:could not find cls: %s\n", ename);
320                                 return ret;
321                         }
322                         
323                         return cls.inheritsToStringArray();
324                         
325
326                 }
327                 Gee.HashMap<string,Gee.HashMap<string,JsRender.NodeProp>> node_defaults;
328                 Gee.HashMap<string,Gee.ArrayList<JsRender.NodeProp>> child_defaults;
329                 
330                 public void init_node_defaults()
331                 {
332                         this.node_defaults = new Gee.HashMap<string,Gee.HashMap<string,JsRender.NodeProp>>();
333                         
334                         // this lot could probably be configured?
335                         
336                         // does this need to add properties to methods?
337                         // these are fake methods.
338                         
339                         
340                         
341                    
342                         this.add_node_default("Gtk.ComboBox", "has_entry", "false");
343                         this.add_node_default("Gtk.Expander", "label", "Label"); 
344                          
345                         this.add_node_default("Gtk.Frame", "label", "Label"); 
346                         
347                         this.add_node_default("Gtk.Grid", "columns", "2"); // special properties (is special as it's not part of the standard?!)
348                         //this.add_node_default("Gtk.Grid", "rows", "2");  << this is not really that important..
349                  
350                         this.add_node_default("Gtk.HeaderBar", "title", "Window Title");
351                         this.add_node_default("Gtk.Label", "label", "Label"); // althought the ctor asks for string.. - we can use label after ctor.
352                  
353                         this.add_node_default("Gtk.Scale", "orientation");
354                          
355                         this.add_node_default("Gtk.ToggleButton", "label", "Label");  
356                         this.add_node_default("Gtk.MenuItem", "label", "Label");
357                         this.add_node_default("Gtk.CheckItem", "label", "Label");                       
358                         this.add_node_default("Gtk.RadioMenuItem", "label", "Label");
359                         this.add_node_default("Gtk.TearoffMenuItem", "label", "Label");
360                         
361                         // not sure how many of these 'attributes' there are - documenation is a bit thin on the ground
362                         this.add_node_default("Gtk.CellRendererText",    "markup_column", "-1");
363                         this.add_node_default("Gtk.CellRendererText",           "text_column","-1");
364                         this.add_node_default("Gtk.CellRendererPixBuf",  "pixbuf_column", "-1");
365                         this.add_node_default("Gtk.CellRendererToggle",  "active_column", "-1");                        
366
367                         //foreground
368                         //foreground-gdk
369                         
370                         
371                          
372                         // treeviewcolumn
373                         
374                 }
375                 
376                 
377                 
378                 
379                 private void add_node_default_from_ctor_all()
380         {
381
382                         var pr = (Project.Gtk) this.project;
383                         
384                          
385                          
386                         foreach(var key in   pr.gir_cache.keys) {
387                                 var gir = pr.gir_cache.get(key);
388                                 GLib.debug("building drop list for package %s", key);
389                                 this.add_node_default_from_ctor_package(gir.classes);
390                         }       
391                 }
392
393                 private void add_node_default_from_ctor_package(Gee.HashMap<string,GirObject> classes)
394                 {
395                         
396
397                         
398                         foreach(var cls in classes.values) {
399                                 GLib.debug("building drop list for class %s.%s", cls.package, cls.name);
400                                 this.add_node_default_from_ctor_classes(cls);
401                         }
402                  
403                 }
404                 
405                 private void add_node_default_from_ctor_classes(GirObject cls)
406                 {
407                         if (cls.ctors.has_key("new")) {
408                                 this.add_node_default_from_ctor(cls.ctors.get("new"));
409                                 return; // and no more.
410                         }
411                         // does not have new ?? needed?
412                         foreach(var ctor in cls.ctors.values) {
413                                 this.add_node_default_from_ctor(ctor);
414                                 break;
415                         
416                         }
417                 }
418                 
419                 
420                 
421                 
422                 
423                 
424                 private void add_node_default_from_ctor(GirObject ctor )
425                 {
426                         var cname = ctor.gparent.fqn();
427                         GLib.debug("Add node from ctor %s:%s", ctor.gparent.fqn(), ctor.name);
428                         if (!this.node_defaults.has_key(cname)) {
429                                 this.node_defaults.set(cname, new Gee.HashMap<string,JsRender.NodeProp>());
430                         }
431                         
432                         if (ctor.paramset == null) {
433                                 return;
434                         }
435                         
436                         var defs=  this.node_defaults.get(cname);
437                         
438                         
439                          
440                         GLib.debug("ctor: %s: %s", cname , ctor.name);
441                          
442                         
443                         // assume we are calling this for a reason...
444                         // get the first value params.
445                          
446                                 //gtk box failing
447                         //GLib.debug("No. of parmas %s %d", cls, ctor.params.size);
448                           
449                     foreach (var prop in ctor.paramset.params) {
450                             string[] opts;
451                             
452                             if (defs.has_key(prop.name)) {
453                                 continue;
454                         }
455                         var sub = this.getClass(prop.type);
456                             
457                            // GLib.debug("adding property from ctor : %s, %s, %s  [%s]", cname , prop.name, prop.type, sub == null ? "-" : sub.nodetype);
458  
459                             if (sub != null) { // can't add child classes here...
460                             
461                                     GLib.debug("skipping ctor argument proprty is an object");
462                                     continue;
463                             }
464                             sub = this.getDelegate(prop.type);
465                              if (sub != null) { // can't add child classes here...
466                                 this.node_defaults.get(cname).set(prop.name, new JsRender.NodeProp.raw(prop.name, prop.type, sub.sig));
467                                 continue;
468                             }
469                             
470                             // FIXME!!! - what about functions
471                             
472                             var dval = "";
473                             switch (prop.type) {
474                                     case "int":
475                                             dval = "0";break;
476                                     case "string": 
477                                             dval = ""; break;
478                                     // anything else?
479                                     
480                                     default: // enam? or bool?
481                                             this.typeOptions(cname, prop.name, prop.type, out opts);
482                                             dval = opts.length > 0 ? opts[0] : "";
483                                             break;
484                             }
485                             
486                             this.node_defaults.get(cname).set(prop.name, new JsRender.NodeProp.prop( prop.name, prop.type, dval));
487                     
488                             
489                              
490                     }
491                 }
492                 
493                 private void add_node_default(string cname, string propname, string val = "")
494                 {
495                         if (!this.node_defaults.has_key(cname)) {
496                                 var add = new Gee.HashMap<string, JsRender.NodeProp>();
497                                 this.node_defaults.set(cname, add);
498                         }
499                         // this recurses...
500                         var cls = this.getClass(cname);
501                         if (cls == null) {
502                                 GLib.debug("invalid class name %s", cname);
503                                 return;
504                         }
505                         var ar = cls.props;
506                         
507                         // liststore.columns - exists as a property but does not have a type (it's an array of typeofs()....
508                         if (ar.has_key(propname) && ar.get(propname).type != "") { // must have  type (otherwise special)
509                                 //GLib.debug("Class %s has property %s from %s - adding normal property", cls, propname, ar.get(propname).asJSONString());
510                                 var add = ar.get(propname).toNodeProp(this, cname); // our nodes dont have default values.
511                                 add.val = val;
512                                 this.node_defaults.get(cname).set(propname, add);
513                                 return;
514                                 
515                         } 
516                         //GLib.debug("Class %s has property %s - adding special property", cls, propname);                      
517                         this.node_defaults.get(cname).set(propname,
518                                 new  JsRender.NodeProp.special( propname, val) 
519                         );
520
521                         
522
523                 
524                 }
525                 private void init_child_defaults()
526                 {
527                         this.child_defaults = new Gee.HashMap<string,Gee.ArrayList<JsRender.NodeProp>>();
528                         
529                         this.add_child_default("Gtk.Fixed", "x", "int", "0");
530                         this.add_child_default("Gtk.Fixed", "y", "int", "0");
531                         this.add_child_default("Gtk.Layout", "x", "int", "0");
532                         this.add_child_default("Gtk.Layout", "y", "int", "0");
533                         this.add_child_default("Gtk.Grid", "colspan", "int", "1");
534                         //this.add_child_default("Gtk.Grid", "height", "int", "1");                     
535                         this.add_child_default("Gtk.Stack", "stack_name", "string", "name");
536                         this.add_child_default("Gtk.Stack", "stack_title", "string", "title");  
537                         
538                         
539                 }
540                 private void add_child_default(string cls, string propname, string type, string val)
541                 {
542                         if (!this.child_defaults.has_key(cls)) {
543                                 this.child_defaults.set(cls, new Gee.ArrayList<JsRender.NodeProp>());
544                         }
545                         
546                         
547                         this.child_defaults.get(cls).add( new JsRender.NodeProp.prop(propname, type, val));
548                 
549                 }
550                  
551                 public Gee.ArrayList<string> packages(Project.Gtk gproject)
552                 {
553                         var vapidirs = gproject.vapidirs();
554                         var ret =  new Gee.ArrayList<string>();
555                         ret.add_all(this.package_cache);
556                         for(var i = 0; i < vapidirs.length;i++) {
557                                 var add = this.loadPackages(vapidirs[i]);
558                                 for (var j=0; j < add.size; j++) {
559                                         if (ret.contains(add.get(j))) {
560                                                 continue;
561                                         }
562                                         ret.add(add.get(j));
563                                 }
564                                 
565                         }
566                         
567                         return ret;
568                 }
569                 // get a list of available vapi files...
570                 
571                 public  Gee.ArrayList<string>  loadPackages(string dirname)
572                 {
573
574                         var ret = new  Gee.ArrayList<string>();
575                         //this.package_cache = new Gee.ArrayList<string>();
576                         
577                         if (!GLib.FileUtils.test(dirname,  FileTest.IS_DIR)) {
578                                 print("opps package directory %s does not exist", dirname);
579                                 return ret;
580                         }
581                          
582                         var dir = File.new_for_path(dirname);
583                         
584                         
585                         try {
586                                 var file_enum = dir.enumerate_children(
587                                         GLib.FileAttribute.STANDARD_DISPLAY_NAME, 
588                                         GLib.FileQueryInfoFlags.NONE, 
589                                         null
590                                 );
591                         
592                          
593                                 FileInfo next_file; 
594                                 while ((next_file = file_enum.next_file(null)) != null) {
595                                         var fn = next_file.get_display_name();
596                                         if (!Regex.match_simple("\\.vapi$", fn)) {
597                                                 continue;
598                                         }
599                                         ret.add(Path.get_basename(fn).replace(".vapi", ""));
600                                 }       
601                         } catch(GLib.Error e) {
602                                 print("oops - something went wrong scanning the packages\n");
603                         }
604                         return ret;
605                         
606                          
607                 }
608                 public override bool  typeOptions(string fqn, string key, string type, out string[] opts) 
609                 {
610                         opts = {};
611                         if (type == ""  ) { // empty type   dont try and fill in options
612                                 return false;
613                         }
614                         GLib.debug("get typeOptions %s (%s)%s", fqn, type, key);
615                         if (type.up() == "BOOL" || type.up() == "BOOLEAN") {
616                                 opts = { "true", "false" };
617                                 return true;
618                         }
619  
620                         var gir= Gir.factoryFqn(this.project,type) ;  // not get class as we are finding Enums.
621                         if (gir == null) {
622                                 GLib.debug("could not find Gir data for %s\n", key);
623                                 return false;
624                         }
625                         //print ("Got type %s", gir.asJSONString());
626                         if (gir.nodetype != "Enum") {
627                                 return false;
628                         }
629                         string[] ret = {};
630                         var iter = gir.consts.map_iterator();
631                         while(iter.next()) {
632                                 
633                                 ret  += (type + "." + iter.get_value().name);
634                         }
635                         
636                         if (ret.length > 0) {
637                                 opts = ret;
638                                 return true;
639                         }
640                         
641                          
642                         return false;
643                          
644                 }
645                 
646                  
647                 
648                 
649                 void add_classes_from_method(GirObject cls, string method , Gee.ArrayList<string> ret)
650                 {
651                         
652                         //GLib.debug("add_classes_from_method %s, %s", cls.fqn(), method);
653                         // does class have this method?
654                         if (!cls.methods.has_key(method)) {
655                                 GLib.debug("skip  %s does not have method %s", cls.fqn(), method);
656                                 return;
657                         }
658                         // add all the possible classes to ret based on first arguemnt?
659                         var m = cls.methods.get(method);
660                         
661                         if (m.paramset.params.size < 1) {
662                                 GLib.debug("%s: %s does not have any params?", cls.fqn(), method);
663                                 return;
664                         }
665                                 
666                         
667                         
668                         var ty = m.paramset.params.get(0).type;
669                         GLib.debug("add  %s   method %s arg0 = %s", cls.fqn(), method, ty);
670                         this.addRealClasses(ret, ty);
671                         // skip dupe // skip depricated
672                         // skip not object // skip GLib.Object (base)
673                         
674                         
675                         //if (cls.fqn() == "GLib.Menu" && method == "append_submenu") {
676                         //      ty = m.paramset.params.get(1).type;
677                         //      GLib.debug("add  %s   method %s arg1 = %s", cls.fqn(), method, ty);
678                         //      this.addRealClasses(ret, ty);
679                         //}
680                          
681                 }
682                 
683                 void addRealClasses(Gee.ArrayList<string>  ret, string cn, bool allow_root = false)
684                 {
685                         if (!cn.contains(".")) {
686                                 return;
687                         }
688                         
689                         var w = this.getClass(cn);
690                         if (w == null) {
691                                 return;
692                         }
693                         
694                         if (w.nodetype != "Class" && w.nodetype != "Interface" ) {
695                                 return;
696                         }
697                         if (ret.contains(cn)) {
698                                 return;
699                         }
700                         
701                         if (!allow_root && w.implements.contains("Gtk.Native")) { // removes popover + window
702                                 return;
703                         }
704                         
705                         if (!w.is_deprecated &&  !w.is_abstract && w.nodetype == "Class" ) {
706                         ret.add(cn);
707                         }
708                         
709                         
710                         
711                         
712                 foreach (var str in w.implementations) {
713                         var c = this.getClass(str);
714                         if (c.is_deprecated || c.is_abstract) {
715                                 continue;
716                                 }
717                                 if (ret.contains(str)) {
718                                         continue;
719                                 }
720                                 if (!allow_root && c.implements.contains("Gtk.Native")) { // removes popover + window
721                                         continue;
722                                 }
723                                 
724                                 
725                                 
726                                 ret.add(str);
727                 }
728                 }
729                         
730                 
731                 /**
732                   this is the real list of objects that appear in the add object pulldown
733                   @param in_rval "*top" || "Gtk.Widget"
734                   
735                 */
736                 public override Gee.ArrayList<string> getChildList(string in_rval, bool with_props)
737         {
738                 
739                 GLib.debug("getChildList %s %s", in_rval, with_props ? "(with props)" : "");
740                 
741                 //return this.original_getChildList(  in_rval, with_props);
742                 var pr = (Project.Gtk) this.project;
743                 if (with_props && pr.child_list_cache_props.has_key(in_rval)) {
744                         return pr.child_list_cache_props.get(in_rval);
745                 }
746                 if (!with_props && pr.child_list_cache.has_key(in_rval)) {
747                                 return pr.child_list_cache.get(in_rval);
748                 }
749                 
750                 // CACHE ?      
751                 var ret = new Gee.ArrayList<string>();
752                 
753                 if (in_rval == "*top") {
754                         // everythign that's not depricated and extends Gtk.Widget
755                         // even a gtk window and about dialog are widgets
756                         this.addRealClasses(ret, "Gtk.Widget", true);
757                         
758                         return ret;
759                         
760                 
761                 
762                 }
763                 var cls = this.getClass(in_rval);
764                 if (cls == null) {
765                         GLib.debug("could not get class for %s", in_rval);
766                         return ret;
767                         }
768                 
769                 // look through methods of in_rval
770                 // set_X << ignore
771                 // probably methods:
772                 this.add_classes_from_method(cls, "add_controller", ret);
773                 this.add_classes_from_method(cls, "add_shortcut", ret);
774                 this.add_classes_from_method(cls, "add_tick_callback", ret); // wtf does this do.
775                 this.add_classes_from_method(cls, "append", ret);
776                 this.add_classes_from_method(cls, "append_column", ret); // columnview column
777                 this.add_classes_from_method(cls, "append_item", ret); // GLib.Menu 
778                 //this.add_classes_from_method(cls, "append_submenu", ret); // GLib.Menu - complicated to support
779                 this.add_classes_from_method(cls, "attach", ret); // grid column                
780                 this.add_classes_from_method(cls, "pack_start", ret); // headerbar (also has pack end?)
781                 
782                   // add_controller 1st arge = ??
783                   // add_menomic_label ??? << no ???
784                   // add_shortcut? 
785                  // add_tick_callback ?
786                  // append << core one to add stuff..
787                  
788                 if (!with_props) {
789                         
790                         pr.child_list_cache.set(in_rval, ret);
791                         return ret; 
792                 }
793                 foreach(var pn in cls.props.values) {
794
795                         if (!pn.is_writable ) {
796                                 GLib.debug("Skip (not write)  %s : (%s) %s", cls.fqn(), pn.type , pn.name);
797                                 continue;
798                         }
799                         // if (&& !pn.ctor_only << we add these?
800                         // are they really available ?
801                         GLib.debug("Add %s : (%s) %s", cls.fqn(), pn.type , pn.name);                   
802                         this.addRealClasses(ret, pn.type);
803                 }
804                 
805                 pr.child_list_cache_props.set(in_rval, ret);            
806                 
807                 return ret;
808                 
809                 
810         }
811         
812         public void buildChildListForDroppingProject()
813         {
814
815                         this.load();
816                         var pr = (Project.Gtk) this.project;
817                         
818                         if (pr.dropList != null) {
819                                 GLib.debug("Drop list alreayd loaded");
820                                 return;
821                         }
822                          
823                         pr.dropList = new Gee.HashMap<string,Gee.ArrayList<string>>();
824                         foreach(var key in   pr.gir_cache.keys) {
825                                 var gir = pr.gir_cache.get(key);
826                                 GLib.debug("building drop list for package %s", key);
827                                 this.buildChildListForDropping(key, gir.classes);
828                         }       
829                 }
830
831                 public void buildChildListForDropping(string pkg, Gee.HashMap<string,GirObject> classes)
832                 {
833                         
834
835                         
836                         foreach(var cls in classes.keys) {
837                                 GLib.debug("building drop list for class %s.%s", pkg, cls);
838                                 this.buildDropList(pkg + "." + cls, this.getChildList(pkg + "." + cls, true));
839                         }
840                         this.buildDropList("*top", this.getChildList("*top", true));
841                 }
842                 
843                  
844         
845         public void buildDropList(string parent, Gee.ArrayList<string> children) 
846         {
847                 
848                 var pr = (Project.Gtk) this.project;
849                 foreach(var c in children) {
850                         if (!pr.dropList.has_key(c)) {
851
852                                 pr.dropList.set(c, new Gee.ArrayList<string>());
853                                 }
854                         var dl = pr.dropList.get(c);
855                         if (dl.contains(parent)) {
856                                 continue;
857                         }
858                         GLib.debug("%s[] = %s", c, parent);
859                         dl.add(parent);
860                 }
861         
862         
863         }
864         
865                 public override Gee.ArrayList<string> getDropList(string rval)
866                 {
867                         this.buildChildListForDroppingProject();
868                         var pr = (Project.Gtk) this.project;
869                         if (!pr.dropList.has_key(rval)) {
870                                 GLib.debug("returning empty drop list for  %s", rval);
871                                 return new Gee.ArrayList<string>();
872                         }
873                         GLib.debug("returning %d items in drop list  %s", pr.dropList.get(rval).size, rval);                    
874                         return  pr.dropList.get(rval);
875
876                         
877                 }
878                  
879                  
880                 public override JsRender.Node fqnToNode(string fqn) 
881                 {
882                         this.load();    
883                         var ret = new JsRender.Node();
884                         ret.setFqn(fqn);
885                         if (!this.node_defaults.has_key(fqn)) {
886                                 return ret;
887                         }
888
889                         foreach (var nv in this.node_defaults.get(fqn).values) {
890                                 ret.add_prop(nv.dupe());
891                         }
892                         return ret;
893                         
894                         
895                         
896                 }
897                 
898                 
899                 
900     }
901 }
902