Palete/Gtk.js
[app.Builder.js] / Palete / Gtk.js
1 //<Script type="text/javascript">
2  
3 Gio = imports.gi.Gio;
4 GIRepository  = imports.gi.GIRepository;
5 GObject= imports.gi.GObject;
6 xml     = imports.libxml;
7 console = imports.console;
8 XObject = imports.XObject.XObject;
9
10 Base = imports.Palete.Base.Base;
11 File = imports.File.File;
12 //----------------------- our roo verison
13
14
15
16
17 Gtk = XObject.define(
18     function(cfg) {
19         
20        
21         // various loader methods..
22           this.map = [];
23         this.load();
24         this.proplist = {};
25         this.comments = { }; 
26         // no parent...
27         
28        
29     },
30     Base,
31     {
32         name : 'Gtk',
33         
34         load: function () {
35                 
36          
37         
38             var data = File.read(__script_path__ +'/GtkUsage.txt');
39           // print(data);
40             data  = data.split(/\n/g);
41             var state = 0;
42             var cfg = [];
43             var left = [];
44             var right = [];
45             
46             data.forEach( function(d) {
47                 if (!d.length || d.match(/^\s+$/) || d.match(/^\s*\//)) { //empty
48                     return;
49                 }
50                 if (d.match(/^left:/)) { 
51                     state = 1;
52                     if (left.length ){
53                         
54                         cfg.push({
55                             left : left,
56                             right: right
57                         });
58                         }
59                     left = [];
60                     right = [];
61                     return;
62                 }
63                 if (d.match(/^right:/)) { 
64                     state = 2;
65                     return;
66                 }
67                 if (state == 1) {
68                     left.push(d.replace(/\s+/g, ''));
69                     return;
70                 }
71                 right.push(d.replace(/\s+/g, ''));
72                 //Seed.quit();
73                
74             }); 
75             if (left.length ){
76                         
77                 cfg.push({
78                     left : left,
79                     right: right
80                 });
81             }
82             this.map = cfg;
83              
84         },
85         
86         
87         commentLoad : function(ns)
88         {
89              
90             if (typeof(this.comments[ns]) != 'undefined') {
91                 return;
92             }
93
94             console.log("LOAD DOCS: " + ns);
95             var gi = GIRepository.Repository.get_default();
96             var ver = gi.get_version(ns);
97             if (!ver) {
98                 this.comments[ns] = {};
99                 return;
100             }
101             var ret = { };
102
103             // no idea why this is broken on my build system.
104             function getAttribute(n, name){
105                 var properties = n.properties;
106                 while (properties){
107                     if (properties.name == name)
108                          return properties.children.content;
109                      properties = properties.next
110                 }
111                 return null;
112             }
113                  
114          
115             function walk(element, path) {
116                  
117                  
118                 if (!element) {
119                     return;
120                 }
121                 
122                 var n =  getAttribute(element, 'name') ;
123                 //console.log("WALK" + n);
124                 if (element.name == 'signal') {
125                     path += '.signal';
126                 } 
127                 if (n) {
128                     path += path.length ? '.' : '';
129                     path += n;
130                 }
131                 if (element.name == 'return-value') {
132                     path += '.return-value';
133                 }
134                 
135                 
136              
137                 var d =   getAttribute(element,'doc');
138                 if (d) {
139                  //   Seed.print(path + ':' + d);
140                     ret[path] = d;
141                 }
142                 
143                 var child = element.children;
144
145                 while (child){
146                     //console.log(child.tag);
147                     if (child.type == "element"){
148                         walk (child, path);
149                     }
150                     child = child.next;
151                 }
152             }
153             
154             var pth = GIRepository.Repository.get_search_path ();
155             
156             
157             var gir_path = pth[0].replace(/lib\/girepository-1.0/, 'share\/gir-1.0');
158            
159             
160             //console.log(fn);
161             var  fn = gir_path + '/'+ ns + '-' + ver + '.gir';
162            // console.log(fn);
163             
164             if (!File.exists(fn)) {
165                 console.log('missing docc file ' + fn);
166                 this.comments[ns] = {};
167                 
168                 return;
169             }
170             var doc = xml.parseFile(fn);
171             //console.log("xmldoc?" + doc);
172             walk (doc.root, '');
173             //console.dump(ret);
174             this.comments[ns] = ret;
175             //console.dump(ret);
176
177         },
178        
179         
180         doc : function(what) {
181             var ns = what.split('.').shift();
182             this.commentLoad(ns);
183             return typeof(this.comments[ns][what]) == 'undefined' ?  '' : this.comments[ns][what];
184         },
185   
186         getPropertiesFor: function(ename, type)
187         {
188             //print("Loading for " + ename);
189             
190             if (typeof(this.proplist[ename]) != 'undefined') {
191                 //print("using cache");
192                 return this.proplist[ename][type];
193             }
194             // use introspection to get lists..
195             var gi = GIRepository.Repository.get_default();
196             var es = ename.split('.');
197             
198             imports.gi[es[0]];
199             var bi = gi.find_by_name(es[0], es[1]);
200             
201             if (!bi) {
202                 print("COULND NOT FIND BY NAME");
203                 return [];
204             }
205             var etype = bi.get_type();;
206             var meth = etype == GIRepository.InfoType.INTERFACE ?
207                 [ 
208                     'interface_info_get_n_properties',
209                     'interface_info_get_property',
210                     'interface_info_get_n_signals',
211                     'interface_info_get_signal',
212                     'interface_info_get_n_methods',
213                     'interface_info_get_method'
214                 ] : [ 
215                     'object_info_get_n_properties',
216                     'object_info_get_property',
217                     'object_info_get_n_signals',
218                     'object_info_get_signal',
219                     'object_info_get_n_methods',
220                     'object_info_get_method'
221                 ]; 
222             
223             
224             this.proplist[ename] = {}
225             this.proplist[ename]['props'] = [];
226             this.proplist[ename]['events'] = [];
227             this.proplist[ename]['methods'] = [];
228             this.proplist[ename]['inherits']= [];
229             
230             var plist = this.proplist[ename]['props'] ;
231             var elist = this.proplist[ename]['events'];
232             var mlist = this.proplist[ename]['methods'];
233             var ilist = this.proplist[ename]['inherits'];
234              /*
235              we need...
236              p.name
237             p.type
238             p.desc
239             p.sig */
240             
241             // properties.. -- and parent ones...!!!
242             for (var i =0;i <  GIRepository[meth[0]](bi); i++) {
243                 var prop = GIRepository[meth[1]](bi,i);  
244                 var n_original =  prop.get_name();
245                 
246                 var flags =  GIRepository.property_info_get_flags(prop); // check for readonly..
247                 
248                 
249                 var ty = this.typeToName(GIRepository.property_info_get_type(prop));
250                 var flags = GIRepository.property_info_get_flags(prop);
251                 print (n_original +":"+ ty);
252                 if (ty === false) {
253                     continue;
254                 }
255                 var add = {
256                      name :  n_original.replace(/\-/g, '_'),
257                      type :  ty,
258                      desc : this.doc(ename + '.' + n_original),
259                      sig : '',
260                      ctor_only : (flags  & GObject.ParamFlags.CONSTRUCT_ONLY) > 0
261                 }
262                 plist.push(add)
263             }
264            
265            
266            
267            
268            
269             // signals..
270             
271             for (var i =0;i <  GIRepository[meth[2]](bi); i++) {
272                 var prop =GIRepository[meth[3]](bi,i);  
273                 var n_original =  prop.get_name();
274                 // print ('signal: ' + n_original); 
275                 var add = {
276                     name :  n_original.replace(/\-/g, '_'),
277                     type : 'function', //???
278                     desc : this.doc(ename + '.signal.' + n_original),
279                     sig  : this.genSkel(prop) // fixme..
280                 }
281                 elist.push(add);
282             }
283             // methods
284             
285             for (var i =0;i <  GIRepository[meth[4]](bi); i++) {
286                 var prop = GIRepository[meth[5]](bi,i);  
287                 var n_original =  prop.get_name();
288                 print(ename +": ADD method: " + n_original );
289                 //var flags = GIRepository.property_info_get_flags(prop);
290                 
291                 if (n_original.match(/^new/)) {
292                     var add = {
293                         name :  n_original.replace(/\-/g, '_'),
294                         type : 'ctor', //???
295                         desc : '',
296                         //desc : this.doc(ename + "."+ n_original)
297                     };
298                     this.genParams(prop,add);
299                     mlist.push(add);
300                     continue;
301                 }
302                 continue;
303                 // not sure why we need all the other ones...
304                 //if (!(flags & GIRepository.FunctionInfoFlags.IS_METHOD)) {
305                 //    continue;
306                 //}
307                 // print ('signal: ' + n_original); 
308                 var add = {
309                     name :  n_original.replace(/\-/g, '_'),
310                     type : 'function', //???
311                     desc : '', //this.doc(ename + '.' + n_original)
312                 };
313                 this.genParams(prop,add);
314                 mlist.push(add);
315             }
316             
317             
318             
319             
320             
321             
322             if (etype == GIRepository.InfoType.INTERFACE ) {
323                // print("SKIPPING PARENT - it's an interface?!?!");
324                   return;
325             }
326             
327             // parent!!?!!?
328             var pi = GIRepository.object_info_get_parent(bi);
329             
330             if (pi) {
331                 
332                    
333                 var pname = pi.get_namespace() + '.' + pi.get_name();
334                 this.getPropertiesFor(pname, 'props');
335                 
336                 
337                 elist.push.apply(elist,this.proplist[pname]['events']);
338                 plist.push.apply(plist,this.proplist[pname]['props']);
339                 ilist.push(pname);
340                 ilist.push.apply(ilist,this.proplist[pname]['inherits']);
341                 
342                 this.overrides(mlist, this.proplist[pname]['methods']);
343                 
344                 
345             } else {
346                 print("NO PARENT FOUND?");
347             }
348             
349             // implements needs to be more carefull as it could add dupes..
350             // use the parent implements list to ensure no dupes..
351             for(var i =0; i < GIRepository.object_info_get_n_interfaces(bi); i++) {
352                  
353                 var prop = GIRepository.object_info_get_interface(bi,i);
354                 var iface = prop.get_namespace() +'.'+ prop.get_name();
355                 if ( ilist.indexOf(iface) > -1) {
356                     continue;
357                 }
358                 this.getPropertiesFor(iface, 'props'); // just load one of them..
359                 ilist.push(iface);
360                 
361                 elist.push.apply(elist,this.proplist[iface]['events']);
362                 plist.push.apply(plist,this.proplist[iface]['props']);
363                 this.overrides(mlist, this.proplist[pname]['methods']);
364             }
365             function sfunc(a,b) {
366                 if (a.name == b.name) return 0;
367                 return a.name > b.name ? 1 : -1
368             }
369             plist.sort(sfunc);
370             elist.sort(sfunc);
371             mlist.sort(sfunc);
372             
373             return this.proplist[ename][type];
374             
375         },
376         genParams: function(sig, meth)
377         {
378             var args = ['self'];
379             var ret = "\n";
380             meth.ret_type = this.typeToName(GIRepository.callable_info_get_return_type(sig));
381             // might be a numbeR??
382             meth.params = [];
383             for(var a_i  =0; a_i   < GIRepository.callable_info_get_n_args(sig); a_i++) {
384                 var arg = GIRepository.callable_info_get_arg(sig, a_i);
385                 print(arg.get_name());
386                 print(arg.get_type());
387                 meth.params.push({
388                     name  : arg.get_name(),
389                     type : this.typeToName(arg.get_type(), true)
390                 });
391             }
392             
393                 
394             
395             
396         },
397         genSkel: function(sig) // should really use genParams...
398         {
399             var args = ['self'];
400             var ret = "\n";
401             var ret_type = this.typeToName(GIRepository.callable_info_get_return_type(sig));
402             // might be a numbeR??
403             if (ret_type == 'boolean') {
404                 ret = "    return false;\n";
405             }
406             for(var a_i  =0; a_i   < GIRepository.callable_info_get_n_args(sig); a_i++) {
407                 var arg = GIRepository.callable_info_get_arg(sig, a_i);
408                 
409                 args.push(arg.get_name());
410             }
411             return 'function (' + args.join(', ') + ") {\n" + ret + "}"; 
412                 
413             
414             
415         },
416         typeToName  : function (type_info, allow_iface) // find type for properties or arguments.
417         {
418             print(type_info);
419             if (type_info == 17) {
420                 return 'integer';
421             }
422             var x = GIRepository.type_info_get_tag(type_info);
423             print(x);
424             var ty = GIRepository.type_tag_to_string( GIRepository.type_info_get_tag(type_info));
425             print(ty);
426            
427             if ((ty == 'void') && GIRepository.type_info_is_pointer(type_info)) {
428                 return false;
429             }
430             if (ty == 'array') {
431                 return false; // unspported   
432             }
433             if (ty != 'interface') {
434                 return ty;
435             }
436             // we can accept enum types here..
437             var interface_info = GIRepository.type_info_get_interface(type_info);
438             var interface_type = interface_info.get_type();
439             
440             if (!allow_iface && interface_type != GIRepository.InfoType.ENUM) {
441                 return false;
442             }
443             return interface_info.get_namespace() + '.' + interface_info.get_name();
444             
445         },
446         /**
447          * merge two proprety arrays' ignoring what's overrriden.
448          * 
449          */
450         
451         
452         overrides : function (top, bottom)
453         {
454             function inTop(b)
455             {
456                 return !top.every(function(t) {
457                     if (t.name == b.name) {
458                         return false;
459                     }
460                     return true;
461                 });
462             }
463             bottom.forEach(function(e) {
464                 if (!inTop(e)) {
465                     top.push(e);
466                 }
467             });
468             
469         },
470         
471         /**
472          * guess type..
473          * 
474          */
475         findType : function (data, prop, value)
476         {
477             // specials??
478             if ((prop == '|xns') || (prop == 'xtype'))  {
479                 return 'string';
480             }
481             
482             var qname = this.guessName(data);
483             if (prop[0] == '|') {
484                 prop= prop.substring(1);
485             }
486             
487             var prs = this.getPropertiesFor(qname, 'props');
488             var ret = false;
489             prs.forEach(function(e) {
490                 if (ret !== false) {
491                     return; // got it.
492                 }
493                 if (e.name == prop) {
494                     ret = e;
495                 }
496                 
497             });
498             if (!ret) {
499                 return Base.prototype.findType(data, prop,value);
500             }
501              
502             // got the type
503             return ret.type;
504         },
505         
506         findOptions : function(ename)
507         {
508             
509             var es = ename.split('.');
510             if (es.length !=2) {
511                 return Base.prototype.findOptions(ename);
512             }
513             var gi = GIRepository.Repository.get_default();
514             var bi = gi.find_by_name(es[0], es[1]);
515             var etype = GIRepository.object_info_get_type(bi);
516             if (etype != GIRepository.InfoType.ENUM) {
517                 console.log("Options not handled yet!!!");
518                 return false;
519             }
520             var ret = [];
521             // got an enum.. let's return the values..
522             for(var i =0; i < bi.get_n_values(); i++) {
523                  
524                   var prop = bi.get_value(i);
525                    
526                 
527                   ret.push( ename + '.' + prop.get_name().toUpperCase() ) 
528             }
529             return ret;
530         },
531         /**
532          * determine the packing types..
533          */
534         getDefaultPack: function(pname, cname) {
535             var list = this.getPackingList(pname,cname);
536            // console.dump(list);
537             
538             
539             if (!list.every(function(e) { return e.name != 'add'; })) {
540                 return 'add'; // add is in our list..?? what about args..?!?
541             }
542             function toRet(e) {
543                 var ret = [e.name];
544                 e.params.forEach(function(p,i) {
545                     if (ret === false) { return; } // skip broken..
546                     if (i==0) { return; } // skip first..
547                     if (p.type == 'boolean') {
548                         ret.push('false');
549                         return;
550                     }
551                     if (p.type == 'number') {
552                         ret.push('0');
553                         return;
554                     }
555                     if (p.type == 'uint') {
556                         ret.push('0');
557                         return;
558                     }
559                     ret = false; // invalid!
560                 });
561                 return ret === false ? false : ret.join(',');
562             };
563             var packret = false;
564             list.every(function(e) {
565                 
566                 packret = toRet(e);
567                 //print("DEFAULT PACK TEST : " + e.name + " : " +packret);
568                 if (packret !== false) {
569                     return false;
570                 }
571                 return true; // continue
572             });
573             //print("DEFAULT PACK: " + packret);
574             // should we do best match..?
575             return packret;
576         },
577         /**
578          * get packing list..
579          */
580         getPackingList :function (pname, cname)
581         {
582             var funcs = this.getPropertiesFor(pname,'methods');
583             //print("getPackingList : ALL FUNCS");
584             //console.dump(funcs);
585             var ret = [];
586             var _this = this;
587             // let's assume top down...
588             var inherits = [ cname ];
589             inherits.push.apply(inherits, this.getPropertiesFor(cname,'inherits'));
590             funcs.forEach(function(m) {
591                 if (m.params.length && (typeof(m.params[0].type) == 'string') &&
592                     inherits.indexOf(m.params[0].type) > -1) {
593                     ret.push(m);
594                 }
595             });
596             return ret; 
597         }
598         
599         
600     }
601 );
602