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