e0b913177f2756796d2240d10a93e1850923595c
[roobuilder] / src / Palete / Roo.vala
1 using Gtk;
2
3 namespace Palete {
4
5         
6 /*      
7         
8         
9     public class Introspect.El : Object
10     {
11         public enum eltype { 
12             NS,
13             CLASS,
14             METHOD,
15             PROP
16         }
17                 
18             
19         public eltype type;
20     }
21
22 */
23     public class Roo : Palete {
24                 
25                 Gee.ArrayList<string> top_classes;
26                 public static Gee.HashMap<string,GirObject>? classes_cache = null;
27                 public static Gee.ArrayList<string>? top_classes_cache = null;
28  
29         public Roo(Project.Project project)
30         {
31
32
33             
34             aconstruct(project);
35             this.name = "Roo";
36                         this.top_classes =  new Gee.ArrayList<string>();
37  
38                         
39                         this.load(); // ? initialize the roodata?
40
41         }
42
43                 Gee.HashMap<string,GirObject> propsFromJSONArray(string type, Json.Array ar, GirObject cls)
44                 {
45
46                         var ret = new Gee.HashMap<string,GirObject>();
47                         
48                         for (var i =0 ; i < ar.get_length(); i++) {
49                                 var o = ar.get_object_element(i);
50                                 var name = o.get_string_member("name"); 
51                                 var prop = new GirObject(type, name );  
52                                  
53                                 prop.type        = o.get_string_member("type");
54                                 prop.doctxt  = o.get_string_member("desc");
55                                 prop.propertyof = o.has_member("memberOf") ? o.get_string_member("memberOf") : "";
56                                 if (prop.propertyof.length < 1)  {
57                                         prop.propertyof = cls.name;
58                                 }
59                                 
60                                 // this is the function default.
61                                 prop.sig = o.has_member("sig") ? o.get_string_member("sig") : "";
62                                 
63                                 if (o.has_member("optvals")  ) {
64                                         var oar = o.get_array_member("optvals");
65                                         
66                                         for (var oi = 0; oi < oar.get_length(); oi++) {
67                                                 prop.optvalues.add(oar.get_string_element(oi));
68                                         }
69                                         
70                                 }       
71                                 
72                                 //print(type + ":" + name +"\n");
73                                 ret.set(name,prop);
74                         }
75                         return ret;
76                 }
77                 
78                 
79                 public override void  load () {
80
81                         if (this.classes != null) {
82                                 return;
83                         }
84                         if (Roo.classes_cache != null) {
85                                 this.classes = Roo.classes_cache;
86                                 this.top_classes = Roo.top_classes_cache ;
87                                 return;
88                         }
89                         
90                         
91                         // this.loadUsageFile(BuilderApplication.configDirectory() + "/resources/RooUsage.txt");
92                         this.classes = new Gee.HashMap<string,GirObject>();
93                         var add_to =  new Gee.HashMap<string,Gee.ArrayList<string>>();
94                                 
95                         var pa = new Json.Parser();
96                         try { 
97                                 pa.load_from_file(BuilderApplication.configDirectory() + "/resources/roodata.json");
98                         } catch(GLib.Error e) {
99                                 GLib.error("Could not load %s",BuilderApplication.configDirectory() + "/resources/roodata.json");
100                         }
101                         var node = pa.get_root();
102
103                         var clist =  node.get_object(); /// was in data... .get_object_member("data");
104                         clist.foreach_member((o , key, value) => {
105                                 //print("cls:" + key+"\n");
106                          
107                                 var cls = new GirObject("class", key);  
108                                 cls.props = this.propsFromJSONArray("prop", value.get_object().get_array_member("props"),cls);
109                                 cls.signals = this.propsFromJSONArray("signal", value.get_object().get_array_member("events"),cls);
110                                 
111                                 
112                                 if (value.get_object().has_member("methods")) {
113                                         cls.methods = this.propsFromJSONArray("method", value.get_object().get_array_member("methods"),cls);
114                                 }
115                                 if (value.get_object().has_member("implementations")) {
116                                         var vcn = value.get_object().get_array_member("implementations");
117                                         for (var i =0 ; i < vcn.get_length(); i++) {
118                                                 cls.implementations.add(vcn.get_string_element(i));
119                                                 //break; << why!?!
120                                         }                               
121                                 }
122                                 // tree children = 
123                                 
124                                 if (value.get_object().has_member("tree_children")) {
125                                         var vcn = value.get_object().get_array_member("tree_children");                         
126                                         for (var i =0 ; i < vcn.get_length(); i++) {
127                                                 var ad_c = vcn.get_string_element(i);
128                                                 if (!cls.valid_cn.contains(ad_c)) {
129                                                         cls.valid_cn.add( ad_c );
130                                                 }
131                                                 if (!add_to.has_key(ad_c)) {
132                                                         add_to.set(ad_c, new Gee.ArrayList<string>());
133                                                 }
134                                                 if (!add_to.get(ad_c).contains(cls.name)) {
135                                                         add_to.get(ad_c).add(cls.name);
136                                                 }
137                                         }
138                                 }
139                                 
140                                 
141                                 
142                                 
143                                 // tree parent
144                                 
145                                 if (value.get_object().has_member("tree_parent")) {
146                                         var vcn = value.get_object().get_array_member("tree_parent");
147                                         for (var i =0 ; i < vcn.get_length(); i++) {
148                                                 if ("builder" == vcn.get_string_element(i)) {
149                                                         // this class can be added to the top level.
150                                                         GLib.debug("Add %s to *top", cls.name);
151                                                         
152                                                         this.top_classes.add(cls.name);
153                                                         break;
154                                                 }
155                                                 
156                                         }
157                                 }
158  
159                                 this.classes.set(key, cls);
160                         });
161                         
162                         // look for properties of classes, that are atually clasess
163                         // eg. Roo.data.Store has proxy and reader..
164                         
165                         
166                         foreach(var cls in this.classes.values) {
167                                 foreach(var gir_obj in cls.props.values) {
168                                         var types = gir_obj.type.split("|");
169                                         for(var i =0; i < types.length; i++) {
170                                                 var type = types[i];
171                                         
172                                                 if (/^Roo\./.match(type) && classes.has_key(type)) {
173                                                         
174                                                          
175                                                         cls.valid_cn.add(type + ":" +   gir_obj.name );
176                                                         // Roo.bootstrap.panel.Content:east
177                                                         // also means that  Roo.bootstrap.panel.Grid:east works
178                                                         var prop_type = classes.get(type);
179                                                         foreach(var imp_str in prop_type.implementations) {
180                                                                 //GLib.debug("addChild for %s - child=  %s:%s", cls.name, imp_str, gir_obj.name);
181                                                                 cls.valid_cn.add(imp_str + ":" +    gir_obj.name);
182                                                                 if (!add_to.has_key(imp_str)) {
183                                                                         add_to.set( imp_str, new Gee.ArrayList<string>());
184                                                                 }
185                                                                 if (!add_to.get( imp_str).contains(cls.name)) {
186                                                                         add_to.get( imp_str ).add(cls.name );
187                                                                 }
188                                                                 
189                                                         }
190                                                         
191                                                         
192                                                         if (!add_to.has_key( type)) {
193                                                                 add_to.set( type, new Gee.ArrayList<string>());
194                                                         }
195                                                         if (!add_to.get(type).contains(cls.name)) {
196                                                                 add_to.get( type ).add(cls.name );
197                                                         }
198                                                 }
199                                         }
200                                 }
201                                  
202                         }
203                         foreach(var cls in this.classes.values) {
204                                 if (add_to.has_key(cls.name)) {
205                                         cls.can_drop_onto = add_to.get(cls.name);
206                                 }
207                         }
208                         Roo.classes_cache = this.classes;
209                         Roo.top_classes_cache  = this.top_classes;
210                 }
211                   
212                         
213                 public string doc(string what) {
214                         return "";
215                         /*var ns = what.split(".")[0];
216
217
218                         
219                         
220                                 var gir =  Gir.factory(ns);
221                                 return   gir.doc(what);
222                                 */
223                                 
224                         //return typeof(this.comments[ns][what]) == 'undefined' ?  '' : this.comments[ns][what];
225                 }
226
227                 // does not handle implements...
228                 public override GirObject? getClass(string ename)
229                 {
230                         this.load();
231                         return this.classes.get(ename);
232                         
233                 }
234                 
235                  
236                 
237                 public override Gee.HashMap<string,GirObject> getPropertiesFor(string ename, JsRender.NodePropType ptype)
238                 {
239                         //print("Loading for " + ename);
240                         
241
242                         this.load();
243                                         // if (typeof(this.proplist[ename]) != 'undefined') {
244                                         //print("using cache");
245                                  //   return this.proplist[ename][type];
246                                 //}
247                                 // use introspection to get lists..
248                  
249                         
250                         var cls = this.classes.get(ename);
251                         var ret = new Gee.HashMap<string,GirObject>();
252                         if (cls == null) {
253                                 print("could not find class: %s\n", ename);
254                                 return ret;
255                                 //throw new Error.INVALID_VALUE( "Could not find class: " + ename);
256                 
257                         }
258
259                         //cls.parseProps();
260                         //cls.parseSignals(); // ?? needed for add handler..
261                         //cls.parseMethods(); // ?? needed for ??..
262                         //cls.parseConstructors(); // ?? needed for ??..
263
264                         //cls.overlayParent();
265
266                         switch  (ptype) {
267                                 
268                                 
269                                 case JsRender.NodePropType.PROP:
270                                         return  this.filterProps(cls.props);
271                                 case JsRender.NodePropType.LISTENER:
272                                         return cls.signals;
273                                 case JsRender.NodePropType.METHOD:
274                                         return ret;
275                                 case JsRender.NodePropType.CTOR:
276                                         return ret;
277                                 default:
278                                         GLib.error( "getPropertiesFor called with: " + ptype.to_string()); 
279                                         //var ret = new Gee.HashMap<string,GirObject>();
280                                         //return ret;
281                         
282                         }
283                 
284         
285                 //cls.overlayInterfaces(gir);
286
287
288                          
289                 }
290                 
291                 // removes all the properties where the type contains '.' ?? << disabled now..
292                 
293                 public Gee.HashMap<string,GirObject>  filterProps(Gee.HashMap<string,GirObject> props)
294                 {
295                         // we shold probably cache this??
296                         
297                         var outprops = new Gee.HashMap<string,GirObject>(); 
298                         
299                         foreach(var k in props.keys) {
300                                 var val = props.get(k);
301                                 
302                                 // special props..
303                                 switch(k) {
304                                         case "listeners" : 
305                                                 continue;
306                                         default:
307                                                 break;
308                                 }
309                                 
310                                  
311                                  //if (!val.type.contains(".")) {
312                                         outprops.set(k,val);
313                                         continue;
314                                  //}
315                                 
316                                 
317                                  
318                                 // do nothing? - classes not allowed?
319                                 
320                         }
321                         
322                         
323                         return outprops;
324                 
325                 
326                 }
327                 
328                 
329                 public string[] getInheritsFor(string ename)
330                 {
331                         string[] ret = {};
332                         var es = ename.split(".");
333                         var gir = Gir.factory(null, es[0]);
334                         
335                         var cls = gir.classes.get(es[1]);
336                         if (cls == null) {
337                                 return ret;
338                         }
339                         return cls.inheritsToStringArray();
340                         
341
342                 }
343
344  
345                 /*
346                  *  Pulldown options for type
347                  */
348                 public override bool typeOptions(string fqn, string key, string type, out string[] opts) 
349                 {
350                         opts = {};
351                         print("get typeOptions %s (%s)%s", fqn, type, key);
352                         if (type.up() == "BOOL" || type.up() == "BOOLEAN") {
353                                 opts = { "true", "false" };
354                                 return true;
355                          }
356                          
357                          var props = this.getPropertiesFor(fqn, JsRender.NodePropType.PROP);
358                          if (!props.has_key(key)) {
359                                  print("prop %s does not have key %s\n", fqn, key);
360                                  return false;
361                          }
362                          var pr = props.get(key);
363                          if (pr.optvalues.size < 1) {
364                                  print("prop %s no optvalues for %s\n", fqn, key);
365                                  return false;
366                          }
367                          string[] ret = {};
368                          for(var i = 0; i < pr.optvalues.size; i++) {
369                                  ret += pr.optvalues.get(i);
370                          }
371                          opts = ret;
372                          print("prop %s returning optvalues for %s\n", fqn, key);
373                          return true;
374                          
375                 }
376                 public override  Gee.ArrayList<CompletionProposal> suggestComplete(
377                                 JsRender.JsRender file,
378                                 JsRender.Node? node,
379                                 JsRender.NodeProp? xxprop,
380                                 string complete_string
381                 ) { 
382                         
383                         var ret =  new Gee.ArrayList<CompletionProposal>();
384                         return ret;
385                         /*
386                         // completion rules??
387                         
388                         // Roo......
389                         
390                         // this. (based on the node type)
391                         // this.xxx // Node and any determination...
392                         
393                         if (complete_string.index_of(".",0) < 0) {
394                                 // string does not have a '.'
395                                 // offer up this / Roo / javascript keywords... / look for var string = .. in the code..
396                                 for(var i = 0; i <  JsRender.Lang.match_strings.size ; i++) {
397                                         var str = JsRender.Lang.match_strings.get(i);
398                                         if (complete_string != str && str.index_of(complete_string,0) == 0 ) { 
399                                                 // should we ignore exact matches... ???tr,str,
400                                                 var sci = new CompletionProposal(str,str, "javascript: " + str);
401                                                 ret.add(sci);
402                                                  
403                                         }
404                                         
405                                         
406                                 }
407                                 if (complete_string != "Roo" && "Roo".index_of(complete_string,0) == 0 ) { 
408                                         // should we ignore exact matches... ???
409                                 
410                                         var sci = new CompletionProposal("Roo - A Roo class","Roo", "Roo Library");
411                                         ret.add(sci);
412                                  
413                                 }
414                                 if (complete_string != "_this" && "_this".index_of(complete_string,0) == 0 ) { 
415                                         // should we ignore exact matches... ???
416                                         var sci = new CompletionProposal("_this - Reference to the global pointer to the files main class instance",
417                                                 "_this", "Reference to the global pointer to the files main class instance");
418                                         ret.add(sci);
419                                          
420                                 }
421                                 return ret;
422                         }
423                         // got at least one ".".
424                         var parts = complete_string.split(".");
425                         var curtype = "";
426                         var cur_instance = false;
427                         if (parts[0] == "this") {
428                                 // work out from the node, what the type is...
429                                 if (node == null) {
430                                         print("node is empty - no return\n");
431                                         return ret; // no idea..
432                                 }
433                                 curtype = node.fqn();
434                                 cur_instance = true;
435                         }
436                         if (parts[0] == "Roo") {        
437                                 curtype = "Roo";
438                                 cur_instance = false;
439                         }
440                         
441                         var prevbits = parts[0] + ".";
442                         for(var i =1; i < parts.length; i++) {
443                                 print("matching %d/%d\n", i, parts.length);
444                                 var is_last = i == parts.length -1;
445                                 
446                                 // look up all the properties of the type...
447                                 var cls = this.getClass(curtype);
448                                 if (cls == null) {
449                                         print("could not get class of curtype %s\n", curtype);
450                                         return ret;
451                                 }
452
453                                 if (!is_last) {
454                                 
455                                         // only exact matches from here on...
456                                         if (cur_instance) {
457                                                 if (cls.props.has_key(parts[i])) {
458                                                         var prop = cls.props.get(parts[i]);
459                                                         if (prop.type.index_of(".",0) > -1) {
460                                                                 // type is another roo object..
461                                                                 curtype = prop.type;
462                                                                 prevbits += parts[i] + ".";
463                                                                 continue;
464                                                         }
465                                                         return ret;
466                                                 }
467                                                 
468                                                 
469                                                 
470                                                 // check methods?? - we do not export that at present..
471                                                 return ret;      //no idea...
472                                         }
473                                 
474                                         // not a instance..
475                                         //look for child classes.
476                                         var citer = this.classes.map_iterator();
477                                         var foundit = false;
478                                         while (citer.next()) {
479                                                 var scls = citer.get_key();
480                                                 var look = prevbits + parts[i];
481                                                 if (scls.index_of(look,0) != 0) {
482                                                         continue;
483                                                 }
484                                                 // got a starting match..
485                                                 curtype = look;
486                                                 cur_instance = false;
487                                                 foundit =true;
488                                                 break;
489                                         }
490                                         if (!foundit) {
491                                                 return ret;
492                                         }
493                                         prevbits += parts[i] + ".";
494                                         continue;
495                                 }
496                                 // got to the last element..
497                                 print("Got last element\n");
498                                 if (curtype == "") { // should not happen.. we would have returned already..
499                                         return ret;
500                                 }
501                                 print("Got last element type %s\n",curtype);
502                                 if (!cur_instance) {
503                                         print("matching instance");
504                                         // it's a static reference..
505                                         var citer = this.classes.map_iterator();
506                                         while (citer.next()) {
507                                                 var scls = citer.get_key();
508                                                 var look = prevbits + parts[i];
509                                                 if (parts[i].length > 0 && scls.index_of(look,0) != 0) {
510                                                         continue;
511                                                 }
512                                                 
513                                                 // got a starting match..
514                                                 var sci = new CompletionProposal(scls,scls,scls);
515                                                 ret.add(sci);
516                                         }
517                                         return ret;
518                                 }
519                                 print("matching property");
520                                 
521                                 
522                                 
523                                 var citer = cls.methods.map_iterator();
524                                 while (citer.next()) {
525                                         var prop = citer.get_value();
526                                         // does the name start with ...
527                                         if (parts[i].length > 0 && prop.name.index_of(parts[i],0) != 0) {
528                                                 continue;
529                                         }
530                                         // got a matching property...
531                                         // return type?
532                                         
533                                         
534                                         var sci = new CompletionProposal(prop.name + prop.sig + " :  ("+ prop.propertyof + ")",
535                                                 prevbits + prop.name + "(",prop.doctxt);
536                                         ret.add(sci);
537                                          
538                                 }
539                                 
540                                 // get the properties / methods and subclasses.. of cls..
541                                 // we have cls.. - see if the string matches any of the properties..
542                                 citer = cls.props.map_iterator();
543                                 while (citer.next()) {
544                                         var prop = citer.get_value();
545                                         // does the name start with ...
546                                         if (parts[i].length > 0 && prop.name.index_of(parts[i],0) != 0) {
547                                                 continue;
548                                         }
549                                         // got a matching property..
550                                         var sci = new CompletionProposal(prop.name + prop.type + " :  ("+ prop.propertyof + ")",
551                                                 prevbits + prop.name + "(",prop.doctxt);
552                                         ret.add(sci);
553                                 
554                                 }
555                                          
556                                         
557                                 return ret;     
558                                         
559                                         
560                                 
561                                         
562                                 
563                         }
564                         
565                          
566                         
567                         
568                         
569                         
570                         return ret;
571                         */
572                 }
573                 
574                 
575                 public override Gee.ArrayList<string> getChildList(string in_rval, bool with_prop)
576         {
577                 if (this.top_classes.size < 1) {
578                         this.load();
579                 }
580                  
581                  
582                  
583                 var ar = this.top_classes;
584                 if (in_rval != "*top") {
585                         if (this.classes.has_key(in_rval)) {
586                            // some of these children will be eg: Roo.bootstrap.layout.Region:center
587                                 ar = this.classes.get(in_rval).valid_cn;
588                         } else {
589                                 ar = new Gee.ArrayList<string>();
590                         }
591                 }
592                 
593                 if (!with_prop) {
594                         var ret = new Gee.ArrayList<string>();
595                         foreach(var v in ar) {
596                                 if (v.contains(":")) {
597                                         continue;
598                                 }
599                                 ret.add(v);
600                         }
601                         return ret;
602                 }
603                  
604                 GLib.debug("getChildList for %s returns %d items",  in_rval, ar.size);
605                 return ar;      
606                 
607                 //return this.original_getChildList(  in_rval);
608         }
609         
610
611         
612                 public override Gee.ArrayList<string> getDropList(string rval)
613                 {
614                         
615                         if (this.dropCache.has_key(rval)) {
616                                 return this.dropCache.get(rval);
617                         }
618                         // we might be dragging  Roo.bootstrap.layout.Region:center
619                         // in which case we need to lookup Roo.bootstrap.layout.Region
620                         // and see if it's has can_drop_onto
621                         var  ret = new Gee.ArrayList<string>();
622                         var cls = this.classes.get(rval);
623                         // cls can be null.
624                         if (cls == null && rval.contains(":")) {
625                                 var rr = rval.substring(0,rval.index_of(":"));
626                                 GLib.debug("Converted classname to %s", rr);
627                                 cls = this.classes.get(rr);
628                     }
629                         if (cls == null) {
630                                 return ret; //nothing..
631                         }
632                         
633                         foreach(var str in cls.can_drop_onto) {
634
635                                 ret.add(str);
636                         }
637                         //GLib.debug("getDropList for %s return[] %s", rval, string.joinv(", ", ret));
638                         this.dropCache.set(rval,ret);
639                         return ret;
640                                 
641                         
642                         
643                         //return this.default_getDropList(rval);
644                 }       
645                 public override JsRender.Node fqnToNode(string fqn) 
646                 {
647                         var ret = new JsRender.Node();
648                         ret.setFqn(fqn);
649                         // any default requred proerties?
650                         
651                         return ret;
652                         
653                         
654                         
655                 }
656                 
657     }
658     
659     
660                 
661                 
662     
663 }
664