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