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