9d17b09ae97f8fdb396f2cfa7b55075161522b8d
[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                         // completion rules??
677                         
678                         // make sure data is loaded
679                         Gir.factory(this.project,"Gtk");
680                         
681                         // Roo......
682                         
683                         // this. (based on the node type)
684                         // this.xxx // Node and any determination...
685                         
686                         if (complete_string.index_of(".",0) < 0) {
687                                 // string does not have a '.'
688                                 // offer up vala keywords... / _this .. / look for var string = .. in the code..
689                                 
690                                 var max = (int)Vala.TokenType.YIELD +1;
691                                 for (var i =0; i < max;i++) {
692                                         var m = (Vala.TokenType)i;
693                                         var s = m.to_string();
694                                         var ss = s.slice(1,-1); 
695                                         if (s[0] == '`' && GLib.Regex.match_simple("^[a-z]+$", ss) &&
696                                                 complete_string != ss && ss.index_of(complete_string,0) == 0 ) {
697                                                 var sci = new CompletionProposal(ss,ss, "vala : " + ss);
698                                                 ret.add(sci);
699                                         }
700                                 }
701                                 var miter = ((Project.Gtk)this.project).gir_cache.map_iterator();
702                                 while (miter.next()) {
703                                         var ss = miter.get_key();
704                                         
705                                         if (complete_string != ss && ss.index_of(complete_string,0) == 0 ) {
706                                                 var sci = new  CompletionProposal(ss,ss, "vala namespace: " + ss);
707                                                 ret.add(sci);
708                                                 
709                                         }
710                                 }
711                                  
712                                 
713                                 if (complete_string != "_this" && "_this".index_of(complete_string,0) == 0 ) { // should we ignore exact matches... ???
714                                         var sci = new CompletionProposal("_this - the top level element","_this",  
715                                                 "Reference to the container object instance of this file");
716                                         ret.add(sci);
717                                          
718                                 }
719                                 // basic types..
720                                 
721                                 return ret;
722                         }
723                          
724                         
725                          // got at least one ".".
726                         var parts = complete_string.split(".");
727                         var curtype = "";
728                         var cur_instance = false;
729                         if (parts[0] == "this") {
730                                 // work out from the node, what the type is...
731                                 if (node == null) {
732                                         print("node is empty - no return\n");
733                                         return ret; // no idea..
734                                 }
735                                 curtype = "*" +  node.fqn();
736                                 cur_instance = true;
737                         } else {
738                                  if (((Project.Gtk)this.project).gir_cache.get(parts[0]) == null) {
739                                         return ret;
740                                 }
741                                 curtype = parts[0];
742                         }
743                         // all Gtk.... etc.. types...
744                         
745                         
746                         //if (parts[0] == "Roo") {      
747                         //      curtype = "Roo";
748                         //      cur_instance = false;
749                         //}
750                         
751                         var prevbits = parts[0] + ".";
752                         for(var i =1; i < parts.length; i++) {
753                                 print("matching %d/%d\n", i, parts.length);
754                                 var is_last = i == parts.length -1;
755                                 
756                                 
757                                  
758                                 // look up all the properties of the type...
759                                 var cls = this.getClass(curtype);
760                                 if (cls == null && curtype[0] != '*') {
761                                         print("could not get class of curtype %s\n", curtype);
762                                         return ret;
763                                 }
764
765                                 if (!is_last) {
766                                         
767                                         if (curtype[0] == '*' && parts[i] == "el") {
768                                                 curtype = curtype.substring(1);
769                                                 prevbits += parts[i] + ".";
770                                                 continue;
771                                         }
772                                         
773                                         // only exact matches from here on...
774                                         if (cur_instance) {
775                                                 if (cls == null) {
776                                                         return ret;
777                                                 }
778                                                 if (cls.props.has_key(parts[i])) {
779                                                         var clsprop = cls.props.get(parts[i]);
780                                                         if (clsprop.type.index_of(".",0) > -1) {
781                                                                 // type is another roo object..
782                                                                 curtype = clsprop.type;
783                                                                 prevbits += parts[i] + ".";
784                                                                 continue;
785                                                         }
786                                                         return ret;
787                                                 }
788                                                  
789                                                 
790                                                 
791                                                 // check methods?? - we do not export that at present..
792                                                 return ret;      //no idea...
793                                         }
794                                         var look = prevbits + parts[i];
795                                         var scls = this.getClass(look);
796                                         if (scls == null) {
797                                                 return ret;
798                                         }
799                                         curtype = look;
800                                         prevbits += parts[i] + ".";
801                                         continue;
802                                          
803                                 }
804                                 
805                                 // got to the last element..
806                                 print("Got last element\n");
807                                 if (curtype == "") { // should not happen.. we would have returned already..
808                                         return ret;
809                                 }
810                                 print("Got last element type %s\n",curtype);
811                                 if (!cur_instance) {
812                                         print("matching instance");
813                                         // it's a static reference..
814                                         var citer = cls.classes.map_iterator();
815                                         while (citer.next()) {
816                                                 var scls = citer.get_key();
817                                                 
818                                                 if (parts[i].length > 0 && scls.index_of(parts[i],0) != 0) {
819                                                         continue;
820                                                 }
821                                                 // got a starting match..
822                                                 var sci = new CompletionProposal(prevbits + scls,prevbits + scls,scls);
823                                                 ret.add(sci);
824                                          
825                                                  
826                                         }
827                                         // methods.... 
828                                         citer = cls.methods.map_iterator();
829                                         while (citer.next()) {
830                                                 var scls = citer.get_key();
831                                                 
832                                                 if (parts[i].length > 0 && scls.index_of(parts[i],0) != 0) {
833                                                         continue;
834                                                 }
835                                                 // got a starting match..
836                                                 
837                                                 var sci = new CompletionProposal(prevbits + scls  + citer.get_value().sig,prevbits + scls,scls);
838                                                 ret.add(sci);
839                                                  
840                                         }
841                                         
842                                         // enums.... 
843                                         citer = cls.consts.map_iterator();
844                                         while (citer.next()) {
845                                                 var scls = citer.get_key();
846                                                 
847                                                 if (parts[i].length > 0 && scls.index_of(parts[i],0) != 0) {
848                                                         continue;
849                                                 }
850                                                 // got a starting match..
851                                                 var sci = new CompletionProposal(prevbits + scls  + citer.get_value().sig,prevbits + scls,scls);
852                                                 ret.add(sci);
853                                                  
854                                         }
855                                         
856                                         
857                                         return ret;
858                                 }
859                                 print("matching property");
860                                 if (cls == null) {
861                                         return ret;
862                                 }
863                                 
864                                 
865                                 var citer = cls.methods.map_iterator();
866                                 while (citer.next()) {
867                                         var cprop = citer.get_value();
868                                         // does the name start with ...
869                                         if (parts[i].length > 0 && cprop.name.index_of(parts[i],0) != 0) {
870                                                 continue;
871                                         }
872                                         // got a matching property...
873                                         // return type?
874                                         var sci = new CompletionProposal( cprop.name + cprop.sig + " :  ("+ cprop.propertyof + ")",
875                                                         prevbits + cprop.name + "(",cprop.doctxt);
876                                                 ret.add(sci);
877                                                  
878                                           
879                                 }
880                                 
881                                 // get the properties / methods and subclasses.. of cls..
882                                 // we have cls.. - see if the string matches any of the properties..
883                                 citer = cls.props.map_iterator();
884                                 while (citer.next()) {
885                                         var cprop = citer.get_value();
886                                         // does the name start with ...
887                                         if (parts[i].length > 0 && cprop.name.index_of(parts[i],0) != 0) {
888                                                 continue;
889                                         }
890                                         // got a matching property...
891                                         var sci = new CompletionProposal(cprop.name + " : " + cprop.type + " ("+ cprop.propertyof + ")",
892                                                         prevbits + cprop.name,cprop.doctxt);
893                                                 ret.add(sci);
894                                         
895                                         
896                                          
897                                 }
898                                          
899                                         
900                                 return ret;     
901                                         
902                                         
903                                 
904                                         
905                                 
906                         }
907                         
908                          
909                         
910                         
911                         
912                         
913                         return ret;
914                 }
915                 
916                 
917                 void add_classes_from_method(GirObject cls, string method , Gee.ArrayList<string> ret)
918                 {
919                         
920                         //GLib.debug("add_classes_from_method %s, %s", cls.fqn(), method);
921                         // does class have this method?
922                         if (!cls.methods.has_key(method)) {
923                                 GLib.debug("skip  %s does not have method %s", cls.fqn(), method);
924                                 return;
925                         }
926                         // add all the possible classes to ret based on first arguemnt?
927                         var m = cls.methods.get(method);
928                         
929                         if (m.paramset.params.size < 1) {
930                                 GLib.debug("%s: %s does not have any params?", cls.fqn(), method);
931                                 return;
932                         }
933                                 
934                         
935                         
936                         var ty = m.paramset.params.get(0).type;
937                         GLib.debug("add  %s   method %s arg0 = %s", cls.fqn(), method, ty);
938                         this.addRealClasses(ret, ty);
939                         // skip dupe // skip depricated
940                         // skip not object // skip GLib.Object (base)
941                         
942                 }
943                 
944                 void addRealClasses(Gee.ArrayList<string>  ret, string cn, bool allow_root = false)
945                 {
946                         if (!cn.contains(".")) {
947                                 return;
948                         }
949                         
950                         var w = this.getClass(cn);
951                         if (w == null) {
952                                 return;
953                         }
954                         
955                         if (w.nodetype != "Class" && w.nodetype != "Interface" ) {
956                                 return;
957                         }
958                         if (ret.contains(cn)) {
959                                 return;
960                         }
961                         
962                         if (!allow_root && w.implements.contains("Gtk.Native")) { // removes popover + window
963                                 return;
964                         }
965                         
966                         if (!w.is_deprecated &&  !w.is_abstract && w.nodetype == "Class" ) {
967                         ret.add(cn);
968                         }
969                         
970                         
971                         
972                         
973                 foreach (var str in w.implementations) {
974                         var c = this.getClass(str);
975                         if (c.is_deprecated || c.is_abstract) {
976                                 continue;
977                                 }
978                                 if (ret.contains(str)) {
979                                         continue;
980                                 }
981                                 if (!allow_root && c.implements.contains("Gtk.Native")) { // removes popover + window
982                                         continue;
983                                 }
984                                 
985                                 
986                                 
987                                 ret.add(str);
988                 }
989                 }
990                         
991                 
992                 /**
993                   this is the real list of objects that appear in the add object pulldown
994                   @param in_rval "*top" || "Gtk.Widget"
995                   
996                 */
997                 public override Gee.ArrayList<string> getChildList(string in_rval, bool with_props)
998         {
999                 
1000                 GLib.debug("getChildList %s %s", in_rval, with_props ? "(with props)" : "");
1001                 
1002                 //return this.original_getChildList(  in_rval, with_props);
1003                 var pr = (Project.Gtk) this.project;
1004                 if (with_props && pr.child_list_cache_props.has_key(in_rval)) {
1005                         return pr.child_list_cache_props.get(in_rval);
1006                 }
1007                 if (!with_props && pr.child_list_cache.has_key(in_rval)) {
1008                                 return pr.child_list_cache.get(in_rval);
1009                 }
1010                 
1011                 // CACHE ?      
1012                 var ret = new Gee.ArrayList<string>();
1013                 
1014                 if (in_rval == "*top") {
1015                         // everythign that's not depricated and extends Gtk.Widget
1016                         // even a gtk window and about dialog are widgets
1017                         this.addRealClasses(ret, "Gtk.Widget", true);
1018                         
1019                         return ret;
1020                         
1021                 
1022                 
1023                 }
1024                 var cls = this.getClass(in_rval);
1025                 if (cls == null) {
1026                         GLib.debug("could not get class for %s", in_rval);
1027                         return ret;
1028                         }
1029                 
1030                 // look through methods of in_rval
1031                 // set_X << ignore
1032                 // probably methods:
1033                 this.add_classes_from_method(cls, "add_controller", ret);
1034                 this.add_classes_from_method(cls, "add_shortcut", ret);
1035                 this.add_classes_from_method(cls, "add_tick_callback", ret); // wtf does this do.
1036                 this.add_classes_from_method(cls, "append", ret);
1037                 this.add_classes_from_method(cls, "append_column", ret); // columnview column
1038                 this.add_classes_from_method(cls, "append_item", ret); // GLib.Menu
1039                 this.add_classes_from_method(cls, "attach", ret); // grid column                
1040                 this.add_classes_from_method(cls, "pack_start", ret); // headerbar (also has pack end?)
1041                 
1042                   // add_controller 1st arge = ??
1043                   // add_menomic_label ??? << no ???
1044                   // add_shortcut? 
1045                  // add_tick_callback ?
1046                  // append << core one to add stuff..
1047                  
1048                 if (!with_props) {
1049                         
1050                         pr.child_list_cache.set(in_rval, ret);
1051                         return ret; 
1052                 }
1053                 foreach(var pn in cls.props.values) {
1054
1055                         if (!pn.is_writable ) {
1056                                 GLib.debug("Skip (not write)  %s : (%s) %s", cls.fqn(), pn.type , pn.name);
1057                                 continue;
1058                         }
1059                         // if (&& !pn.ctor_only << we add these?
1060                         // are they really available ?
1061                         GLib.debug("Add %s : (%s) %s", cls.fqn(), pn.type , pn.name);                   
1062                         this.addRealClasses(ret, pn.type);
1063                 }
1064                 
1065                 pr.child_list_cache_props.set(in_rval, ret);            
1066                 
1067                 return ret;
1068                 
1069                 
1070         }
1071         
1072         public void buildChildListForDroppingProject()
1073         {
1074
1075                         this.load();
1076                         var pr = (Project.Gtk) this.project;
1077                         
1078                         if (pr.dropList != null) {
1079                                 GLib.debug("Drop list alreayd loaded");
1080                                 return;
1081                         }
1082                          
1083                         pr.dropList = new Gee.HashMap<string,Gee.ArrayList<string>>();
1084                         foreach(var key in   pr.gir_cache.keys) {
1085                                 var gir = pr.gir_cache.get(key);
1086                                 GLib.debug("building drop list for package %s", key);
1087                                 this.buildChildListForDropping(key, gir.classes);
1088                         }       
1089                 }
1090
1091                 public void buildChildListForDropping(string pkg, Gee.HashMap<string,GirObject> classes)
1092                 {
1093                         
1094
1095                         
1096                         foreach(var cls in classes.keys) {
1097                                 GLib.debug("building drop list for class %s.%s", pkg, cls);
1098                                 this.buildDropList(pkg + "." + cls, this.getChildList(pkg + "." + cls, true));
1099                         }
1100                         this.buildDropList("*top", this.getChildList("*top", true));
1101                 }
1102                 
1103                  
1104         
1105         public void buildDropList(string parent, Gee.ArrayList<string> children) 
1106         {
1107                 
1108                 var pr = (Project.Gtk) this.project;
1109                 foreach(var c in children) {
1110                         if (!pr.dropList.has_key(c)) {
1111
1112                                 pr.dropList.set(c, new Gee.ArrayList<string>());
1113                                 }
1114                         var dl = pr.dropList.get(c);
1115                         if (dl.contains(parent)) {
1116                                 continue;
1117                         }
1118                         GLib.debug("%s[] = %s", c, parent);
1119                         dl.add(parent);
1120                 }
1121         
1122         
1123         }
1124         
1125                 public override Gee.ArrayList<string> getDropList(string rval)
1126                 {
1127                         this.buildChildListForDroppingProject();
1128                         var pr = (Project.Gtk) this.project;
1129                         if (!pr.dropList.has_key(rval)) {
1130                                 GLib.debug("returning empty drop list for  %s", rval);
1131                                 return new Gee.ArrayList<string>();
1132                         }
1133                         GLib.debug("returning %d items in drop list  %s", pr.dropList.get(rval).size, rval);                    
1134                         return  pr.dropList.get(rval);
1135
1136                         
1137                 }
1138                  
1139                  
1140                 public override JsRender.Node fqnToNode(string fqn) 
1141                 {
1142                         this.load();    
1143                         var ret = new JsRender.Node();
1144                         ret.setFqn(fqn);
1145                         if (!this.node_defaults.has_key(fqn)) {
1146                                 return ret;
1147                         }
1148
1149                         foreach (var nv in this.node_defaults.get(fqn).values) {
1150                                 ret.add_prop(nv.dupe());
1151                         }
1152                         return ret;
1153                         
1154                         
1155                         
1156                 }
1157                 
1158                 
1159                 
1160     }
1161 }
1162