53873b2e9e74d0157bd6d3bf5c1046fdab7f1d25
[roobuilder] / src / Palete / Gtk.vala
1 using Gtk;
2
3
4 /**
5
6 Palete.map
7  -> contains a list of parent and child classes
8  // eg. what can be added to what.
9  
10 // defaults
11
12 // node properties??
13   (mostly from 
14
15 Known issues with Palete
16
17
18 Object Add:
19
20 SourceView/TextView - can add widget (which doesnt really seem to work) - as it's subclassing a container
21 Gtk.Table - adding children? (nothing is currently allowed.
22
23
24 Properties list 
25 - need to remove widgets from this..
26 - help / show source interface etc..?
27 - make wider?
28
29 Events list
30 - signature on insert
31 - show source interface / help
32
33   
34
35 */
36
37
38
39 namespace Palete {
40
41         
42         
43         
44         
45          
46
47         public class Gtk : Palete {
48                 
49                 public Gee.ArrayList<string> package_cache;
50                 
51                 public Gtk(Project.Project project)
52                 {
53
54                     aconstruct(project);
55                     this.name = "Gtk";
56                     var context = new Vala.CodeContext ();
57                          
58                     this.package_cache = this.loadPackages(Path.get_dirname (context.get_vapi_path("glib-2.0")));
59                     this.package_cache.add_all(
60                             this.loadPackages(Path.get_dirname (context.get_vapi_path("gee-0.8")))
61                     );
62                      
63                    
64                     
65                 }
66                 
67                 
68         // a) build a list of all widgets that can be added generically.
69                 // b) build child list for all containers.
70                 // c) build child list for all widgets (based on properties)
71                 // d) handle oddities?
72                 
73                 public bool loaded = false; // set to false to force a reload
74
75                 public override void  load () 
76                 {
77                         if (this.loaded) {
78                                 return;
79                         }
80                         Gir.factory(this.project, "Gtk"); // triggers a load...
81                          
82                         this.init_node_defaults();
83                         this.add_node_default_from_ctor_all();
84                     this.init_child_defaults();  
85                     
86                     this.loaded = true;
87                          
88                         
89                 }
90                 
91                 
92                 
93           
94                 
95                 public string doc(string what) 
96                 {
97                 var ns = what.split(".")[0];
98                 var gir =  Gir.factory(this.project,ns);
99                         return  ((Gir) gir).doc(what);
100                         
101                     //return typeof(this.comments[ns][what]) == 'undefined' ?  '' : this.comments[ns][what];
102                 }
103
104                         // does not handle implements...
105                 public override GirObject? getClass(string ename)
106                 {
107
108                         var es = ename.split(".");
109                         if (es.length < 2) {
110                                 return null;
111                         }
112                         var gir = Gir.factory(this.project,es[0]);
113                         if (gir == null) {
114                                 return null;
115                         }
116                         return gir.classes.get(es[1]);
117                 
118                 }
119                 
120                 public  GirObject? getDelegate(string ename) 
121                 {
122                         var es = ename.split(".");
123                         if (es.length < 2) {
124                                 return null;
125                         }
126                         var gir = Gir.factory(this.project,es[0]);
127                         if (gir == null) {
128                                 return null;
129                         }
130                         return gir.delegates.get(es[1]);
131                 
132                 }
133
134                 public  GirObject? getClassOrEnum(string ename)
135                 {
136
137                         var es = ename.split(".");
138                         if (es.length < 2) {
139                                 return null;
140                         }
141                         var gir = Gir.factory(this.project,es[0]);
142                         if (gir.classes.has_key(es[1])) {
143                                 return gir.classes.get(es[1]);
144                         }
145                         if (gir.consts.has_key(es[1])) {
146                                 return  gir.consts.get(es[1]);
147                         }
148                         return null;
149                 }
150
151
152                 public override Gee.HashMap<string,GirObject> getPropertiesFor( string ename, JsRender.NodePropType ptype) 
153                 {
154                         //print("Loading for " + ename);
155                     
156
157                         this.load();
158                                 // if (typeof(this.proplist[ename]) != 'undefined') {
159                         //print("using cache");
160                         //   return this.proplist[ename][type];
161                         //}
162                         // use introspection to get lists..
163          
164                         var es = ename.split(".");
165                         var gir = Gir.factory(this.project,es[0]);
166                         if (gir == null) {
167                                 print("WARNING = could not load vapi for %s  (%s)\n", ename , es[0]);
168                                 return new Gee.HashMap<string,GirObject>();
169                         }
170                         var cls = gir.classes.get(es[1]);
171                         if (cls == null) {
172                                 var ret = new Gee.HashMap<string,GirObject>();
173                                 return ret;
174                                 //throw new Error.INVALID_VALUE( "Could not find class: " + ename);
175                         
176                         }
177
178                         //cls.parseProps();
179                         //cls.parseSignals(); // ?? needed for add handler..
180                         //cls.parseMethods(); // ?? needed for ??..
181                         //cls.parseConstructors(); // ?? needed for ??..
182
183                         cls.overlayParent(this.project);
184
185                         switch  (ptype) {
186                                 case JsRender.NodePropType.PROP:
187                                         var ret =  this.filterProps(cls.props);
188                                         // add ctor
189                                         this.add_props_from_ctors(cls, ret);
190                                         return ret;
191                                 case JsRender.NodePropType.LISTENER:
192                                         return this.filterSignals(cls.signals);
193                                 case JsRender.NodePropType.METHOD:
194                                         return cls.methods;
195                                 case JsRender.NodePropType.CTOR:  // needed to query the arguments of a ctor.
196                                         return cls.ctors;
197                                 default:
198                                         GLib.error( "getPropertiesFor called with: " + ptype.to_string());
199                                         //var ret = new Gee.HashMap<string,GirObject>();
200                                         //return ret;
201                                 
202                         }
203                                 
204                         
205                         //cls.overlayInterfaces(gir);
206                      
207                      
208                 }
209                 // get rid of objecst from props list..
210                 public Gee.HashMap<string,GirObject>  filterProps(Gee.HashMap<string,GirObject> props)
211                 {
212                         // we shold probably cache this??
213                         
214                         var outprops = new Gee.HashMap<string,GirObject>(); 
215                         
216                         foreach(var k in props.keys) {
217                                 var val = props.get(k);
218 //                              GLib.debug("FilterProp: %s", k);
219                                 // properties that dont make any sense to display.
220                                 if (
221                                         k == "___" ||
222                                         k == "parent" ||
223                                         k == "default_widget" ||
224                                         k == "root" ||
225                                         k == "layout_manager" || // ??
226                                         k == "widget"  // gestures..
227                                 ) {
228                                         continue;
229                                 }
230                                 
231                                 if (val.is_deprecated) {
232                                         continue;
233                                 }
234                                 if (val.type == "GLib.Object") { /// this is practually everything? ?? shoud we display it as a property?
235                                         continue;
236                                 }
237                                 if (!val.type.contains(".")) {
238                                         outprops.set(k,val);
239                                         continue;
240                                 }
241                                 var cls = this.getClassOrEnum(val.type);
242                                 
243                                 // if cls == null - it's probably a struct? I don't think we handle thses
244                                 if ( cls != null ) { // cls.nodetype == "Enum") {
245                                         // assume it's ok
246                                         outprops.set(k,val);
247                                         continue;
248                                 }
249                                 // do nothing? - classes not allowed?
250                                 
251                         }
252                         
253                         
254                         return outprops;
255                 
256                 
257                 }
258                 
259                 private void add_props_from_ctors(GirObject cls, Gee.HashMap<string,GirObject> props)
260                 {
261                         if (cls.ctors.has_key("new")) {
262                                 this.add_props_from_ctor(cls.ctors.get("new"), props);  
263                                 return;
264                         }
265                         // does not have new ?? needed?
266                         foreach(var ctor in cls.ctors.values) {
267                                 this.add_props_from_ctor(ctor, props);
268                                 break;
269                         
270                         }
271                 }
272                 
273                 private void add_props_from_ctor(GirObject ctor,  Gee.HashMap<string,GirObject> props)
274                 {
275                         var cname = ctor.gparent.fqn();
276                         GLib.debug("Add node from ctor %s:%s", ctor.gparent.fqn(), ctor.name);
277                          
278                         if (ctor.paramset == null) {
279                                 return;
280                         }
281                         
282                          
283                         // assume we are calling this for a reason...
284                         // get the first value params.
285                          
286                                 //gtk box failing
287                         //GLib.debug("No. of parmas %s %d", cls, ctor.params.size);
288                           
289                     foreach (var prop in ctor.paramset.params) {
290  
291                             
292                             if (props.has_key(prop.name)) { // overlap (we assume it's the same..)
293                                 continue;
294                         }
295                         prop.propertyof = cname + "." + ctor.name; // as it's probably not filled in..
296                             
297                             GLib.debug("adding proprty from ctor : %s, %s, %s", cname , prop.name, prop.type);
298
299                              props.set(prop.name, prop);
300                     
301                             
302                              
303                     }
304                 }
305                 
306                 
307                 
308                                 // get rid of depricated from signal list..
309                 public Gee.HashMap<string,GirObject>  filterSignals(Gee.HashMap<string,GirObject> props)
310                 {
311                         // we shold probably cache this??
312                         
313                         var outprops = new Gee.HashMap<string,GirObject>(); 
314                         
315                         foreach(var k in props.keys) {
316                                 var val = props.get(k);
317                                  
318                                 if (val.is_deprecated) {
319                                         continue;
320                                 }
321                                 
322                                 outprops.set(k,val);
323                                         
324                                 // do nothing? - classes not allowed?
325                                 
326                         }
327                         
328                         
329                         return outprops;
330                 
331                 
332                 }
333                 
334                 public string[] getInheritsFor(string ename)
335                 {
336                         string[] ret = {};
337                          
338                         var cls = this.getClass(ename);
339                          
340                         if (cls == null || cls.nodetype != "Class") {
341                                 print("getInheritsFor:could not find cls: %s\n", ename);
342                                 return ret;
343                         }
344                         
345                         return cls.inheritsToStringArray();
346                         
347
348                 }
349                 Gee.HashMap<string,Gee.HashMap<string,JsRender.NodeProp>> node_defaults;
350                 Gee.HashMap<string,Gee.ArrayList<JsRender.NodeProp>> child_defaults;
351                 
352                 public void init_node_defaults()
353                 {
354                         this.node_defaults = new Gee.HashMap<string,Gee.HashMap<string,JsRender.NodeProp>>();
355                         
356                         // this lot could probably be configured?
357                         
358                         // does this need to add properties to methods?
359                         // these are fake methods.
360                         
361                         
362                         
363                    
364                         this.add_node_default("Gtk.ComboBox", "has_entry", "false");
365                         this.add_node_default("Gtk.Expander", "label", "Label"); 
366                          
367                         this.add_node_default("Gtk.Frame", "label", "Label"); 
368                         
369                         this.add_node_default("Gtk.Grid", "columns", "2"); // special properties (is special as it's not part of the standard?!)
370                         //this.add_node_default("Gtk.Grid", "rows", "2");  << this is not really that important..
371                  
372                         this.add_node_default("Gtk.HeaderBar", "title", "Window Title");
373                         this.add_node_default("Gtk.Label", "label", "Label"); // althought the ctor asks for string.. - we can use label after ctor.
374                  
375                         this.add_node_default("Gtk.Scale", "orientation");
376                          
377                         this.add_node_default("Gtk.ToggleButton", "label", "Label");  
378                         this.add_node_default("Gtk.MenuItem", "label", "Label");
379                         this.add_node_default("Gtk.CheckItem", "label", "Label");                       
380                         this.add_node_default("Gtk.RadioMenuItem", "label", "Label");
381                         this.add_node_default("Gtk.TearoffMenuItem", "label", "Label");
382                         
383                         // not sure how many of these 'attributes' there are - documenation is a bit thin on the ground
384                         this.add_node_default("Gtk.CellRendererText",    "markup_column", "-1");
385                         this.add_node_default("Gtk.CellRendererText",           "text_column","-1");
386                         this.add_node_default("Gtk.CellRendererPixBuf",  "pixbuf_column", "-1");
387                         this.add_node_default("Gtk.CellRendererToggle",  "active_column", "-1");                        
388
389                         //foreground
390                         //foreground-gdk
391                         
392                         
393                          
394                         // treeviewcolumn
395                         
396                 }
397                 
398                 
399                 
400                 
401                 private void add_node_default_from_ctor_all()
402         {
403
404                         var pr = (Project.Gtk) this.project;
405                         
406                          
407                          
408                         foreach(var key in   pr.gir_cache.keys) {
409                                 var gir = pr.gir_cache.get(key);
410                                 GLib.debug("building drop list for package %s", key);
411                                 this.add_node_default_from_ctor_package(gir.classes);
412                         }       
413                 }
414
415                 private void add_node_default_from_ctor_package(Gee.HashMap<string,GirObject> classes)
416                 {
417                         
418
419                         
420                         foreach(var cls in classes.values) {
421                                 GLib.debug("building drop list for class %s.%s", cls.package, cls.name);
422                                 this.add_node_default_from_ctor_classes(cls);
423                         }
424                  
425                 }
426                 
427                 private void add_node_default_from_ctor_classes(GirObject cls)
428                 {
429                         if (cls.ctors.has_key("new")) {
430                                 this.add_node_default_from_ctor(cls.ctors.get("new"));
431                                 return; // and no more.
432                         }
433                         // does not have new ?? needed?
434                         foreach(var ctor in cls.ctors.values) {
435                                 this.add_node_default_from_ctor(ctor);
436                                 break;
437                         
438                         }
439                 }
440                 
441                 
442                 
443                 
444                 
445                 
446                 private void add_node_default_from_ctor(GirObject ctor )
447                 {
448                         var cname = ctor.gparent.fqn();
449                         GLib.debug("Add node from ctor %s:%s", ctor.gparent.fqn(), ctor.name);
450                         if (!this.node_defaults.has_key(cname)) {
451                                 this.node_defaults.set(cname, new Gee.HashMap<string,JsRender.NodeProp>());
452                         }
453                         
454                         if (ctor.paramset == null) {
455                                 return;
456                         }
457                         
458                         var defs=  this.node_defaults.get(cname);
459                         
460                         
461                          
462                         GLib.debug("ctor: %s: %s", cname , ctor.name);
463                          
464                         
465                         // assume we are calling this for a reason...
466                         // get the first value params.
467                          
468                                 //gtk box failing
469                         //GLib.debug("No. of parmas %s %d", cls, ctor.params.size);
470                           
471                     foreach (var prop in ctor.paramset.params) {
472                             string[] opts;
473                             
474                             if (defs.has_key(prop.name)) {
475                                 continue;
476                         }
477                         var sub = this.getClass(prop.type);
478                             
479                            // GLib.debug("adding property from ctor : %s, %s, %s  [%s]", cname , prop.name, prop.type, sub == null ? "-" : sub.nodetype);
480  
481                             if (sub != null) { // can't add child classes here...
482                             
483                                     GLib.debug("skipping ctor argument proprty is an object");
484                                     continue;
485                             }
486                             sub = this.getDelegate(prop.type);
487                              if (sub != null) { // can't add child classes here...
488                                 this.node_defaults.get(cname).set(prop.name, new JsRender.NodeProp.raw(prop.name, prop.type, sub.sig));
489                                 continue;
490                             }
491                             
492                             // FIXME!!! - what about functions
493                             
494                             var dval = "";
495                             switch (prop.type) {
496                                     case "int":
497                                             dval = "0";break;
498                                     case "string": 
499                                             dval = ""; break;
500                                     // anything else?
501                                     
502                                     default: // enam? or bool?
503                                             this.typeOptions(cname, prop.name, prop.type, out opts);
504                                             dval = opts.length > 0 ? opts[0] : "";
505                                             break;
506                             }
507                             
508                             this.node_defaults.get(cname).set(prop.name, new JsRender.NodeProp.prop( prop.name, prop.type, dval));
509                     
510                             
511                              
512                     }
513                 }
514                 
515                 private void add_node_default(string cname, string propname, string val = "")
516                 {
517                         if (!this.node_defaults.has_key(cname)) {
518                                 var add = new Gee.HashMap<string, JsRender.NodeProp>();
519                                 this.node_defaults.set(cname, add);
520                         }
521                         // this recurses...
522                         var cls = this.getClass(cname);
523                         if (cls == null) {
524                                 GLib.debug("invalid class name %s", cname);
525                                 return;
526                         }
527                         var ar = cls.props;
528                         
529                         // liststore.columns - exists as a property but does not have a type (it's an array of typeofs()....
530                         if (ar.has_key(propname) && ar.get(propname).type != "") { // must have  type (otherwise special)
531                                 //GLib.debug("Class %s has property %s from %s - adding normal property", cls, propname, ar.get(propname).asJSONString());
532                                 var add = ar.get(propname).toNodeProp(this, cname); // our nodes dont have default values.
533                                 add.val = val;
534                                 this.node_defaults.get(cname).set(propname, add);
535                                 return;
536                                 
537                         } 
538                         //GLib.debug("Class %s has property %s - adding special property", cls, propname);                      
539                         this.node_defaults.get(cname).set(propname,
540                                 new  JsRender.NodeProp.special( propname, val) 
541                         );
542
543                         
544
545                 
546                 }
547                 private void init_child_defaults()
548                 {
549                         this.child_defaults = new Gee.HashMap<string,Gee.ArrayList<JsRender.NodeProp>>();
550                         
551                         this.add_child_default("Gtk.Fixed", "x", "int", "0");
552                         this.add_child_default("Gtk.Fixed", "y", "int", "0");
553                         this.add_child_default("Gtk.Layout", "x", "int", "0");
554                         this.add_child_default("Gtk.Layout", "y", "int", "0");
555                         this.add_child_default("Gtk.Grid", "colspan", "int", "1");
556                         //this.add_child_default("Gtk.Grid", "height", "int", "1");                     
557                         this.add_child_default("Gtk.Stack", "stack_name", "string", "name");
558                         this.add_child_default("Gtk.Stack", "stack_title", "string", "title");  
559                         
560                         
561                 }
562                 private void add_child_default(string cls, string propname, string type, string val)
563                 {
564                         if (!this.child_defaults.has_key(cls)) {
565                                 this.child_defaults.set(cls, new Gee.ArrayList<JsRender.NodeProp>());
566                         }
567                         
568                         
569                         this.child_defaults.get(cls).add( new JsRender.NodeProp.prop(propname, type, val));
570                 
571                 }
572                  
573                 public Gee.ArrayList<string> packages(Project.Gtk gproject)
574                 {
575                         var vapidirs = gproject.vapidirs();
576                         var ret =  new Gee.ArrayList<string>();
577                         ret.add_all(this.package_cache);
578                         for(var i = 0; i < vapidirs.length;i++) {
579                                 var add = this.loadPackages(vapidirs[i]);
580                                 for (var j=0; j < add.size; j++) {
581                                         if (ret.contains(add.get(j))) {
582                                                 continue;
583                                         }
584                                         ret.add(add.get(j));
585                                 }
586                                 
587                         }
588                         
589                         return ret;
590                 }
591                 // get a list of available vapi files...
592                 
593                 public  Gee.ArrayList<string>  loadPackages(string dirname)
594                 {
595
596                         var ret = new  Gee.ArrayList<string>();
597                         //this.package_cache = new Gee.ArrayList<string>();
598                         
599                         if (!GLib.FileUtils.test(dirname,  FileTest.IS_DIR)) {
600                                 print("opps package directory %s does not exist", dirname);
601                                 return ret;
602                         }
603                          
604                         var dir = File.new_for_path(dirname);
605                         
606                         
607                         try {
608                                 var file_enum = dir.enumerate_children(
609                                         GLib.FileAttribute.STANDARD_DISPLAY_NAME, 
610                                         GLib.FileQueryInfoFlags.NONE, 
611                                         null
612                                 );
613                         
614                          
615                                 FileInfo next_file; 
616                                 while ((next_file = file_enum.next_file(null)) != null) {
617                                         var fn = next_file.get_display_name();
618                                         if (!Regex.match_simple("\\.vapi$", fn)) {
619                                                 continue;
620                                         }
621                                         ret.add(Path.get_basename(fn).replace(".vapi", ""));
622                                 }       
623                         } catch(GLib.Error e) {
624                                 print("oops - something went wrong scanning the packages\n");
625                         }
626                         return ret;
627                         
628                          
629                 }
630                 public override bool  typeOptions(string fqn, string key, string type, out string[] opts) 
631                 {
632                         opts = {};
633                         if (type == ""  ) { // empty type   dont try and fill in options
634                                 return false;
635                         }
636                         GLib.debug("get typeOptions %s (%s)%s", fqn, type, key);
637                         if (type.up() == "BOOL" || type.up() == "BOOLEAN") {
638                                 opts = { "true", "false" };
639                                 return true;
640                         }
641  
642                         var gir= Gir.factoryFqn(this.project,type) ;  // not get class as we are finding Enums.
643                         if (gir == null) {
644                                 GLib.debug("could not find Gir data for %s\n", key);
645                                 return false;
646                         }
647                         //print ("Got type %s", gir.asJSONString());
648                         if (gir.nodetype != "Enum") {
649                                 return false;
650                         }
651                         string[] ret = {};
652                         var iter = gir.consts.map_iterator();
653                         while(iter.next()) {
654                                 
655                                 ret  += (type + "." + iter.get_value().name);
656                         }
657                         
658                         if (ret.length > 0) {
659                                 opts = ret;
660                                 return true;
661                         }
662                         
663                          
664                         return false;
665                          
666                 }
667                 
668                 public override  Gee.ArrayList<CompletionProposal> suggestComplete(
669                                 JsRender.JsRender file,
670                                 JsRender.Node? node,
671                                 JsRender.NodeProp? xxxprop, // is this even used?
672                                 string complete_string
673                 ) { 
674                         
675                         var ret =  new Gee.ArrayList<CompletionProposal>();
676                         return ret;
677                         /*
678                         // completion rules??
679                         
680                         // make sure data is loaded
681                         Gir.factory(this.project,"Gtk");
682                         
683                         // Roo......
684                         
685                         // this. (based on the node type)
686                         // this.xxx // Node and any determination...
687                         
688                         if (complete_string.index_of(".",0) < 0) {
689                                 // string does not have a '.'
690                                 // offer up vala keywords... / _this .. / look for var string = .. in the code..
691                                 
692                                 var max = (int)Vala.TokenType.YIELD +1;
693                                 for (var i =0; i < max;i++) {
694                                         var m = (Vala.TokenType)i;
695                                         var s = m.to_string();
696                                         var ss = s.slice(1,-1); 
697                                         if (s[0] == '`' && GLib.Regex.match_simple("^[a-z]+$", ss) &&
698                                                 complete_string != ss && ss.index_of(complete_string,0) == 0 ) {
699                                                 var sci = new CompletionProposal(ss,ss, "vala : " + ss);
700                                                 ret.add(sci);
701                                         }
702                                 }
703                                 var miter = ((Project.Gtk)this.project).gir_cache.map_iterator();
704                                 while (miter.next()) {
705                                         var ss = miter.get_key();
706                                         
707                                         if (complete_string != ss && ss.index_of(complete_string,0) == 0 ) {
708                                                 var sci = new  CompletionProposal(ss,ss, "vala namespace: " + ss);
709                                                 ret.add(sci);
710                                                 
711                                         }
712                                 }
713                                  
714                                 
715                                 if (complete_string != "_this" && "_this".index_of(complete_string,0) == 0 ) { // should we ignore exact matches... ???
716                                         var sci = new CompletionProposal("_this - the top level element","_this",  
717                                                 "Reference to the container object instance of this file");
718                                         ret.add(sci);
719                                          
720                                 }
721                                 // basic types..
722                                 
723                                 return ret;
724                         }
725                          
726                         
727                          // got at least one ".".
728                         var parts = complete_string.split(".");
729                         var curtype = "";
730                         var cur_instance = false;
731                         if (parts[0] == "this") {
732                                 // work out from the node, what the type is...
733                                 if (node == null) {
734                                         print("node is empty - no return\n");
735                                         return ret; // no idea..
736                                 }
737                                 curtype = "*" +  node.fqn();
738                                 cur_instance = true;
739                         } else {
740                                  if (((Project.Gtk)this.project).gir_cache.get(parts[0]) == null) {
741                                         return ret;
742                                 }
743                                 curtype = parts[0];
744                         }
745                         // all Gtk.... etc.. types...
746                         
747                         
748                         //if (parts[0] == "Roo") {      
749                         //      curtype = "Roo";
750                         //      cur_instance = false;
751                         //}
752                         
753                         var prevbits = parts[0] + ".";
754                         for(var i =1; i < parts.length; i++) {
755                                 print("matching %d/%d\n", i, parts.length);
756                                 var is_last = i == parts.length -1;
757                                 
758                                 
759                                  
760                                 // look up all the properties of the type...
761                                 var cls = this.getClass(curtype);
762                                 if (cls == null && curtype[0] != '*') {
763                                         print("could not get class of curtype %s\n", curtype);
764                                         return ret;
765                                 }
766
767                                 if (!is_last) {
768                                         
769                                         if (curtype[0] == '*' && parts[i] == "el") {
770                                                 curtype = curtype.substring(1);
771                                                 prevbits += parts[i] + ".";
772                                                 continue;
773                                         }
774                                         
775                                         // only exact matches from here on...
776                                         if (cur_instance) {
777                                                 if (cls == null) {
778                                                         return ret;
779                                                 }
780                                                 if (cls.props.has_key(parts[i])) {
781                                                         var clsprop = cls.props.get(parts[i]);
782                                                         if (clsprop.type.index_of(".",0) > -1) {
783                                                                 // type is another roo object..
784                                                                 curtype = clsprop.type;
785                                                                 prevbits += parts[i] + ".";
786                                                                 continue;
787                                                         }
788                                                         return ret;
789                                                 }
790                                                  
791                                                 
792                                                 
793                                                 // check methods?? - we do not export that at present..
794                                                 return ret;      //no idea...
795                                         }
796                                         var look = prevbits + parts[i];
797                                         var scls = this.getClass(look);
798                                         if (scls == null) {
799                                                 return ret;
800                                         }
801                                         curtype = look;
802                                         prevbits += parts[i] + ".";
803                                         continue;
804                                          
805                                 }
806                                 
807                                 // got to the last element..
808                                 print("Got last element\n");
809                                 if (curtype == "") { // should not happen.. we would have returned already..
810                                         return ret;
811                                 }
812                                 print("Got last element type %s\n",curtype);
813                                 if (!cur_instance) {
814                                         print("matching instance");
815                                         // it's a static reference..
816                                         var citer = cls.classes.map_iterator();
817                                         while (citer.next()) {
818                                                 var scls = citer.get_key();
819                                                 
820                                                 if (parts[i].length > 0 && scls.index_of(parts[i],0) != 0) {
821                                                         continue;
822                                                 }
823                                                 // got a starting match..
824                                                 var sci = new CompletionProposal(prevbits + scls,prevbits + scls,scls);
825                                                 ret.add(sci);
826                                          
827                                                  
828                                         }
829                                         // methods.... 
830                                         citer = cls.methods.map_iterator();
831                                         while (citer.next()) {
832                                                 var scls = citer.get_key();
833                                                 
834                                                 if (parts[i].length > 0 && scls.index_of(parts[i],0) != 0) {
835                                                         continue;
836                                                 }
837                                                 // got a starting match..
838                                                 
839                                                 var sci = new CompletionProposal(prevbits + scls  + citer.get_value().sig,prevbits + scls,scls);
840                                                 ret.add(sci);
841                                                  
842                                         }
843                                         
844                                         // enums.... 
845                                         citer = cls.consts.map_iterator();
846                                         while (citer.next()) {
847                                                 var scls = citer.get_key();
848                                                 
849                                                 if (parts[i].length > 0 && scls.index_of(parts[i],0) != 0) {
850                                                         continue;
851                                                 }
852                                                 // got a starting match..
853                                                 var sci = new CompletionProposal(prevbits + scls  + citer.get_value().sig,prevbits + scls,scls);
854                                                 ret.add(sci);
855                                                  
856                                         }
857                                         
858                                         
859                                         return ret;
860                                 }
861                                 print("matching property");
862                                 if (cls == null) {
863                                         return ret;
864                                 }
865                                 
866                                 
867                                 var citer = cls.methods.map_iterator();
868                                 while (citer.next()) {
869                                         var cprop = citer.get_value();
870                                         // does the name start with ...
871                                         if (parts[i].length > 0 && cprop.name.index_of(parts[i],0) != 0) {
872                                                 continue;
873                                         }
874                                         // got a matching property...
875                                         // return type?
876                                         var sci = new CompletionProposal( cprop.name + cprop.sig + " :  ("+ cprop.propertyof + ")",
877                                                         prevbits + cprop.name + "(",cprop.doctxt);
878                                                 ret.add(sci);
879                                                  
880                                           
881                                 }
882                                 
883                                 // get the properties / methods and subclasses.. of cls..
884                                 // we have cls.. - see if the string matches any of the properties..
885                                 citer = cls.props.map_iterator();
886                                 while (citer.next()) {
887                                         var cprop = citer.get_value();
888                                         // does the name start with ...
889                                         if (parts[i].length > 0 && cprop.name.index_of(parts[i],0) != 0) {
890                                                 continue;
891                                         }
892                                         // got a matching property...
893                                         var sci = new CompletionProposal(cprop.name + " : " + cprop.type + " ("+ cprop.propertyof + ")",
894                                                         prevbits + cprop.name,cprop.doctxt);
895                                                 ret.add(sci);
896                                         
897                                         
898                                          
899                                 }
900                                          
901                                         
902                                 return ret;     
903                                         
904                                         
905                                 
906                                         
907                                 
908                         }
909                         
910                          
911                         
912                         
913                         
914                         
915                         return ret;
916                         */
917                 }
918                 
919                 
920                 void add_classes_from_method(GirObject cls, string method , Gee.ArrayList<string> ret)
921                 {
922                         
923                         //GLib.debug("add_classes_from_method %s, %s", cls.fqn(), method);
924                         // does class have this method?
925                         if (!cls.methods.has_key(method)) {
926                                 GLib.debug("skip  %s does not have method %s", cls.fqn(), method);
927                                 return;
928                         }
929                         // add all the possible classes to ret based on first arguemnt?
930                         var m = cls.methods.get(method);
931                         
932                         if (m.paramset.params.size < 1) {
933                                 GLib.debug("%s: %s does not have any params?", cls.fqn(), method);
934                                 return;
935                         }
936                                 
937                         
938                         
939                         var ty = m.paramset.params.get(0).type;
940                         GLib.debug("add  %s   method %s arg0 = %s", cls.fqn(), method, ty);
941                         this.addRealClasses(ret, ty);
942                         // skip dupe // skip depricated
943                         // skip not object // skip GLib.Object (base)
944                         
945                 }
946                 
947                 void addRealClasses(Gee.ArrayList<string>  ret, string cn, bool allow_root = false)
948                 {
949                         if (!cn.contains(".")) {
950                                 return;
951                         }
952                         
953                         var w = this.getClass(cn);
954                         if (w == null) {
955                                 return;
956                         }
957                         
958                         if (w.nodetype != "Class" && w.nodetype != "Interface" ) {
959                                 return;
960                         }
961                         if (ret.contains(cn)) {
962                                 return;
963                         }
964                         
965                         if (!allow_root && w.implements.contains("Gtk.Native")) { // removes popover + window
966                                 return;
967                         }
968                         
969                         if (!w.is_deprecated &&  !w.is_abstract && w.nodetype == "Class" ) {
970                         ret.add(cn);
971                         }
972                         
973                         
974                         
975                         
976                 foreach (var str in w.implementations) {
977                         var c = this.getClass(str);
978                         if (c.is_deprecated || c.is_abstract) {
979                                 continue;
980                                 }
981                                 if (ret.contains(str)) {
982                                         continue;
983                                 }
984                                 if (!allow_root && c.implements.contains("Gtk.Native")) { // removes popover + window
985                                         continue;
986                                 }
987                                 
988                                 
989                                 
990                                 ret.add(str);
991                 }
992                 }
993                         
994                 
995                 /**
996                   this is the real list of objects that appear in the add object pulldown
997                   @param in_rval "*top" || "Gtk.Widget"
998                   
999                 */
1000                 public override Gee.ArrayList<string> getChildList(string in_rval, bool with_props)
1001         {
1002                 
1003                 GLib.debug("getChildList %s %s", in_rval, with_props ? "(with props)" : "");
1004                 
1005                 //return this.original_getChildList(  in_rval, with_props);
1006                 var pr = (Project.Gtk) this.project;
1007                 if (with_props && pr.child_list_cache_props.has_key(in_rval)) {
1008                         return pr.child_list_cache_props.get(in_rval);
1009                 }
1010                 if (!with_props && pr.child_list_cache.has_key(in_rval)) {
1011                                 return pr.child_list_cache.get(in_rval);
1012                 }
1013                 
1014                 // CACHE ?      
1015                 var ret = new Gee.ArrayList<string>();
1016                 
1017                 if (in_rval == "*top") {
1018                         // everythign that's not depricated and extends Gtk.Widget
1019                         // even a gtk window and about dialog are widgets
1020                         this.addRealClasses(ret, "Gtk.Widget", true);
1021                         
1022                         return ret;
1023                         
1024                 
1025                 
1026                 }
1027                 var cls = this.getClass(in_rval);
1028                 if (cls == null) {
1029                         GLib.debug("could not get class for %s", in_rval);
1030                         return ret;
1031                         }
1032                 
1033                 // look through methods of in_rval
1034                 // set_X << ignore
1035                 // probably methods:
1036                 this.add_classes_from_method(cls, "add_controller", ret);
1037                 this.add_classes_from_method(cls, "add_shortcut", ret);
1038                 this.add_classes_from_method(cls, "add_tick_callback", ret); // wtf does this do.
1039                 this.add_classes_from_method(cls, "append", ret);
1040                 this.add_classes_from_method(cls, "append_column", ret); // columnview column
1041                 this.add_classes_from_method(cls, "append_item", ret); // GLib.Menu
1042                 this.add_classes_from_method(cls, "attach", ret); // grid column                
1043                 this.add_classes_from_method(cls, "pack_start", ret); // headerbar (also has pack end?)
1044                 
1045                   // add_controller 1st arge = ??
1046                   // add_menomic_label ??? << no ???
1047                   // add_shortcut? 
1048                  // add_tick_callback ?
1049                  // append << core one to add stuff..
1050                  
1051                 if (!with_props) {
1052                         
1053                         pr.child_list_cache.set(in_rval, ret);
1054                         return ret; 
1055                 }
1056                 foreach(var pn in cls.props.values) {
1057
1058                         if (!pn.is_writable ) {
1059                                 GLib.debug("Skip (not write)  %s : (%s) %s", cls.fqn(), pn.type , pn.name);
1060                                 continue;
1061                         }
1062                         // if (&& !pn.ctor_only << we add these?
1063                         // are they really available ?
1064                         GLib.debug("Add %s : (%s) %s", cls.fqn(), pn.type , pn.name);                   
1065                         this.addRealClasses(ret, pn.type);
1066                 }
1067                 
1068                 pr.child_list_cache_props.set(in_rval, ret);            
1069                 
1070                 return ret;
1071                 
1072                 
1073         }
1074         
1075         public void buildChildListForDroppingProject()
1076         {
1077
1078                         this.load();
1079                         var pr = (Project.Gtk) this.project;
1080                         
1081                         if (pr.dropList != null) {
1082                                 GLib.debug("Drop list alreayd loaded");
1083                                 return;
1084                         }
1085                          
1086                         pr.dropList = new Gee.HashMap<string,Gee.ArrayList<string>>();
1087                         foreach(var key in   pr.gir_cache.keys) {
1088                                 var gir = pr.gir_cache.get(key);
1089                                 GLib.debug("building drop list for package %s", key);
1090                                 this.buildChildListForDropping(key, gir.classes);
1091                         }       
1092                 }
1093
1094                 public void buildChildListForDropping(string pkg, Gee.HashMap<string,GirObject> classes)
1095                 {
1096                         
1097
1098                         
1099                         foreach(var cls in classes.keys) {
1100                                 GLib.debug("building drop list for class %s.%s", pkg, cls);
1101                                 this.buildDropList(pkg + "." + cls, this.getChildList(pkg + "." + cls, true));
1102                         }
1103                         this.buildDropList("*top", this.getChildList("*top", true));
1104                 }
1105                 
1106                  
1107         
1108         public void buildDropList(string parent, Gee.ArrayList<string> children) 
1109         {
1110                 
1111                 var pr = (Project.Gtk) this.project;
1112                 foreach(var c in children) {
1113                         if (!pr.dropList.has_key(c)) {
1114
1115                                 pr.dropList.set(c, new Gee.ArrayList<string>());
1116                                 }
1117                         var dl = pr.dropList.get(c);
1118                         if (dl.contains(parent)) {
1119                                 continue;
1120                         }
1121                         GLib.debug("%s[] = %s", c, parent);
1122                         dl.add(parent);
1123                 }
1124         
1125         
1126         }
1127         
1128                 public override Gee.ArrayList<string> getDropList(string rval)
1129                 {
1130                         this.buildChildListForDroppingProject();
1131                         var pr = (Project.Gtk) this.project;
1132                         if (!pr.dropList.has_key(rval)) {
1133                                 GLib.debug("returning empty drop list for  %s", rval);
1134                                 return new Gee.ArrayList<string>();
1135                         }
1136                         GLib.debug("returning %d items in drop list  %s", pr.dropList.get(rval).size, rval);                    
1137                         return  pr.dropList.get(rval);
1138
1139                         
1140                 }
1141                  
1142                  
1143                 public override JsRender.Node fqnToNode(string fqn) 
1144                 {
1145                         this.load();    
1146                         var ret = new JsRender.Node();
1147                         ret.setFqn(fqn);
1148                         if (!this.node_defaults.has_key(fqn)) {
1149                                 return ret;
1150                         }
1151
1152                         foreach (var nv in this.node_defaults.get(fqn).values) {
1153                                 ret.add_prop(nv.dupe());
1154                         }
1155                         return ret;
1156                         
1157                         
1158                         
1159                 }
1160                 
1161                 
1162                 
1163     }
1164 }
1165