82515c31b9976dfca0b014b0336ee523efaf7f99
[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                         // completion rules??
385                         
386                         // Roo......
387                         
388                         // this. (based on the node type)
389                         // this.xxx // Node and any determination...
390                         
391                         if (complete_string.index_of(".",0) < 0) {
392                                 // string does not have a '.'
393                                 // offer up this / Roo / javascript keywords... / look for var string = .. in the code..
394                                 for(var i = 0; i <  JsRender.Lang.match_strings.size ; i++) {
395                                         var str = JsRender.Lang.match_strings.get(i);
396                                         if (complete_string != str && str.index_of(complete_string,0) == 0 ) { 
397                                                 // should we ignore exact matches... ???tr,str,
398                                                 var sci = new CompletionProposal(str,str, "javascript: " + str);
399                                                 ret.add(sci);
400                                                  
401                                         }
402                                         
403                                         
404                                 }
405                                 if (complete_string != "Roo" && "Roo".index_of(complete_string,0) == 0 ) { 
406                                         // should we ignore exact matches... ???
407                                 
408                                         var sci = new CompletionProposal("Roo - A Roo class","Roo", "Roo Library");
409                                         ret.add(sci);
410                                  
411                                 }
412                                 if (complete_string != "_this" && "_this".index_of(complete_string,0) == 0 ) { 
413                                         // should we ignore exact matches... ???
414                                         var sci = new CompletionProposal("_this - Reference to the global pointer to the files main class instance",
415                                                 "_this", "Reference to the global pointer to the files main class instance");
416                                         ret.add(sci);
417                                          
418                                 }
419                                 return ret;
420                         }
421                         // got at least one ".".
422                         var parts = complete_string.split(".");
423                         var curtype = "";
424                         var cur_instance = false;
425                         if (parts[0] == "this") {
426                                 // work out from the node, what the type is...
427                                 if (node == null) {
428                                         print("node is empty - no return\n");
429                                         return ret; // no idea..
430                                 }
431                                 curtype = node.fqn();
432                                 cur_instance = true;
433                         }
434                         if (parts[0] == "Roo") {        
435                                 curtype = "Roo";
436                                 cur_instance = false;
437                         }
438                         
439                         var prevbits = parts[0] + ".";
440                         for(var i =1; i < parts.length; i++) {
441                                 print("matching %d/%d\n", i, parts.length);
442                                 var is_last = i == parts.length -1;
443                                 
444                                 // look up all the properties of the type...
445                                 var cls = this.getClass(curtype);
446                                 if (cls == null) {
447                                         print("could not get class of curtype %s\n", curtype);
448                                         return ret;
449                                 }
450
451                                 if (!is_last) {
452                                 
453                                         // only exact matches from here on...
454                                         if (cur_instance) {
455                                                 if (cls.props.has_key(parts[i])) {
456                                                         var prop = cls.props.get(parts[i]);
457                                                         if (prop.type.index_of(".",0) > -1) {
458                                                                 // type is another roo object..
459                                                                 curtype = prop.type;
460                                                                 prevbits += parts[i] + ".";
461                                                                 continue;
462                                                         }
463                                                         return ret;
464                                                 }
465                                                 
466                                                 
467                                                 
468                                                 // check methods?? - we do not export that at present..
469                                                 return ret;      //no idea...
470                                         }
471                                 
472                                         // not a instance..
473                                         //look for child classes.
474                                         var citer = this.classes.map_iterator();
475                                         var foundit = false;
476                                         while (citer.next()) {
477                                                 var scls = citer.get_key();
478                                                 var look = prevbits + parts[i];
479                                                 if (scls.index_of(look,0) != 0) {
480                                                         continue;
481                                                 }
482                                                 // got a starting match..
483                                                 curtype = look;
484                                                 cur_instance = false;
485                                                 foundit =true;
486                                                 break;
487                                         }
488                                         if (!foundit) {
489                                                 return ret;
490                                         }
491                                         prevbits += parts[i] + ".";
492                                         continue;
493                                 }
494                                 // got to the last element..
495                                 print("Got last element\n");
496                                 if (curtype == "") { // should not happen.. we would have returned already..
497                                         return ret;
498                                 }
499                                 print("Got last element type %s\n",curtype);
500                                 if (!cur_instance) {
501                                         print("matching instance");
502                                         // it's a static reference..
503                                         var citer = this.classes.map_iterator();
504                                         while (citer.next()) {
505                                                 var scls = citer.get_key();
506                                                 var look = prevbits + parts[i];
507                                                 if (parts[i].length > 0 && scls.index_of(look,0) != 0) {
508                                                         continue;
509                                                 }
510                                                 
511                                                 // got a starting match..
512                                                 var sci = new CompletionProposal(scls,scls,scls);
513                                                 ret.add(sci);
514                                         }
515                                         return ret;
516                                 }
517                                 print("matching property");
518                                 
519                                 
520                                 
521                                 var citer = cls.methods.map_iterator();
522                                 while (citer.next()) {
523                                         var prop = citer.get_value();
524                                         // does the name start with ...
525                                         if (parts[i].length > 0 && prop.name.index_of(parts[i],0) != 0) {
526                                                 continue;
527                                         }
528                                         // got a matching property...
529                                         // return type?
530                                         
531                                         
532                                         var sci = new CompletionProposal(prop.name + prop.sig + " :  ("+ prop.propertyof + ")",
533                                                 prevbits + prop.name + "(",prop.doctxt);
534                                         ret.add(sci);
535                                          
536                                 }
537                                 
538                                 // get the properties / methods and subclasses.. of cls..
539                                 // we have cls.. - see if the string matches any of the properties..
540                                 citer = cls.props.map_iterator();
541                                 while (citer.next()) {
542                                         var prop = citer.get_value();
543                                         // does the name start with ...
544                                         if (parts[i].length > 0 && prop.name.index_of(parts[i],0) != 0) {
545                                                 continue;
546                                         }
547                                         // got a matching property..
548                                         var sci = new CompletionProposal(prop.name + prop.type + " :  ("+ prop.propertyof + ")",
549                                                 prevbits + prop.name + "(",prop.doctxt);
550                                         ret.add(sci);
551                                 
552                                 }
553                                          
554                                         
555                                 return ret;     
556                                         
557                                         
558                                 
559                                         
560                                 
561                         }
562                         
563                          
564                         
565                         
566                         
567                         
568                         return ret;
569                 }
570                 
571                 
572                 public override Gee.ArrayList<string> getChildList(string in_rval, bool with_prop)
573         {
574                 if (this.top_classes.size < 1) {
575                         this.load();
576                 }
577                  
578                  
579                  
580                 var ar = this.top_classes;
581                 if (in_rval != "*top") {
582                         if (this.classes.has_key(in_rval)) {
583                            // some of these children will be eg: Roo.bootstrap.layout.Region:center
584                                 ar = this.classes.get(in_rval).valid_cn;
585                         } else {
586                                 ar = new Gee.ArrayList<string>();
587                         }
588                 }
589                 
590                 if (!with_prop) {
591                         var ret = new Gee.ArrayList<string>();
592                         foreach(var v in ar) {
593                                 if (v.contains(":")) {
594                                         continue;
595                                 }
596                                 ret.add(v);
597                         }
598                         return ret;
599                 }
600                  
601                 GLib.debug("getChildList for %s returns %d items",  in_rval, ar.size);
602                 return ar;      
603                 
604                 //return this.original_getChildList(  in_rval);
605         }
606         
607
608         
609                 public override Gee.ArrayList<string> getDropList(string rval)
610                 {
611                         
612                         if (this.dropCache.has_key(rval)) {
613                                 return this.dropCache.get(rval);
614                         }
615                         // we might be dragging  Roo.bootstrap.layout.Region:center
616                         // in which case we need to lookup Roo.bootstrap.layout.Region
617                         // and see if it's has can_drop_onto
618                         var  ret = new Gee.ArrayList<string>();
619                         var cls = this.classes.get(rval);
620                         // cls can be null.
621                         if (cls == null && rval.contains(":")) {
622                                 var rr = rval.substring(0,rval.index_of(":"));
623                                 GLib.debug("Converted classname to %s", rr);
624                                 cls = this.classes.get(rr);
625                     }
626                         if (cls == null) {
627                                 return ret; //nothing..
628                         }
629                         
630                         foreach(var str in cls.can_drop_onto) {
631
632                                 ret.add(str);
633                         }
634                         //GLib.debug("getDropList for %s return[] %s", rval, string.joinv(", ", ret));
635                         this.dropCache.set(rval,ret);
636                         return ret;
637                                 
638                         
639                         
640                         //return this.default_getDropList(rval);
641                 }       
642                 public override JsRender.Node fqnToNode(string fqn) 
643                 {
644                         var ret = new JsRender.Node();
645                         ret.setFqn(fqn);
646                         // any default requred proerties?
647                         
648                         return ret;
649                         
650                         
651                         
652                 }
653                 
654     }
655     
656     
657                 
658                 
659     
660 }
661