resources/RooUsage.txt
[app.Builder.js] / src / Project / Project.vala
1 //<Script type="text/javascript">
2
3 /**
4  * Project Object
5  * 
6  * Projects can only contain one directory... - it can import other projects..(later)
7  * 
8  * we need to sort out that - paths is currently a key/value array..
9  * 
10  * 
11  * 
12  */
13 namespace Project {
14          public errordomain Error {
15                 INVALID_TYPE,
16                 NEED_IMPLEMENTING,
17                 MISSING_FILE,
18                 INVALID_VALUE,
19                 INVALID_FORMAT
20         }
21
22         // static array of all projects.
23         public Gee.HashMap<string,Project>  projects;
24         
25         
26         public bool  projects_loaded = false;
27
28         
29         public class Project : Object {
30                 
31                 public signal void on_changed (); 
32         
33                 public string id;
34                 public string fn = ""; // just a md5...
35                 public string name = "";
36                 public string runhtml = "";
37                 public string base_template = "";
38                 public string rootURL = "";
39                 public Gee.HashMap<string,string> paths;
40                 public Gee.HashMap<string,JsRender.JsRender> files ;
41                 //tree : false,
42                 public  string xtype;
43                 
44                 public Json.Object json_project_data;
45                 public Palete.RooDatabase roo_database;
46                  
47                 bool is_scanned; 
48            
49                 
50                 public Project (string path) {
51                         
52                         this.name = GLib.Path.get_basename(path); // default..
53                         this.json_project_data = new Json.Object();
54                         
55                         this.is_scanned = false;
56                         this.paths = new Gee.HashMap<string,string>();
57                         this.files = new Gee.HashMap<string,JsRender.JsRender>();
58                         //XObject.extend(this, cfg);
59                         //this.files = { }; 
60                         if (path.length > 0) {
61                                 this.paths.set(path, "dir");
62                         }
63                         // dummy roo database...
64                         this.initRooDatabase();
65                         
66                         
67                         
68                 }
69                 public void  initRooDatabase()
70                 {
71                          
72                         this.roo_database = new Palete.RooDatabase.from_project(this);
73                 }
74                 
75                 
76                 
77                 public static void loadAll(bool force = false)
78                 {
79                         if (projects_loaded && !force) {
80                                 return;
81                         }
82
83                         var dirname = GLib.Environment.get_home_dir() + "/.Builder";
84                         var dir = File.new_for_path(dirname);
85                                 if (!dir.query_exists()) {
86                                 dir.make_directory();
87                                 return;
88                         }
89                         projects = new  Gee.HashMap<string,Project>();
90                           
91                    
92                         try {
93                                 var file_enum = dir.enumerate_children(
94                                                                 GLib.FileAttribute.STANDARD_DISPLAY_NAME, 
95                                         GLib.FileQueryInfoFlags.NONE, 
96                                         null
97                                 );
98                                 
99                                  
100                                 FileInfo next_file; 
101                                 while ((next_file = file_enum.next_file(null)) != null) {
102                                                 var fn = next_file.get_display_name();
103                                         if (!Regex.match_simple("\\.json$", fn)) {
104                                                 continue;
105                                         }
106                                         factoryFromFile(dirname + "/" + fn);
107                                 }       
108                         } catch(Error e) {
109                                 GLib.warning("oops - something went wrong scanning the projects\n");
110                         }
111                         
112
113                 }
114
115                 public static Gee.ArrayList<Project> allProjectsByName()
116                 {
117                         var ret = new Gee.ArrayList<Project>();
118                         var iter = projects.map_iterator();
119                                 while (iter.next()) {
120                                         ret.add(iter.get_value());
121                                 }
122                         // fixme -- sort...
123                         return ret;
124                 
125                 }
126                 
127                 public static Project getProject(string name)
128                 {
129                         
130                         var iter = projects.map_iterator();
131                         while (iter.next()) {
132                                 if (iter.get_value().name == name) {
133                                         return iter.get_value();
134                                 }
135                                 
136                         }
137                         
138                         return null;
139                 
140                 }
141                 
142                 public static string listAllToString()
143                 {
144                         var all = new Gee.ArrayList<Project>();
145
146                         var fiter = projects.map_iterator();
147                         
148                         while(fiter.next()) {
149                                 all.add(fiter.get_value());
150                         }
151                         
152                         all.sort((fa,fb) => {
153                                 return ((Project)fa).name.collate(((Project)fb).name);
154
155                         });
156
157                         var iter = all.list_iterator();
158                         var ret = "ID\tName\tDirectory\n";
159                         while (iter.next()) {
160                                 ret += "%s\t%s\t%s\n".printf(
161                                                 iter.get().fn,
162                                                 iter.get().name,
163                                                 iter.get().firstPath()
164                                                 );
165                          
166                                 
167                         }
168                         
169                         return ret;
170                 
171                 }
172                 
173                 
174                 
175                 public static Project getProjectByHash(string fn)
176                 {
177                         
178                         var iter = projects.map_iterator();
179                         while (iter.next()) {
180                                 if (iter.get_value().fn == fn) {
181                                         return iter.get_value();
182                                 }
183                                 
184                         }
185                         
186                         return null;
187                 
188                 }
189                 
190                 // load project data from project file.
191                 public static void   factoryFromFile(string jsonfile)
192                 {
193                          
194                         GLib.debug("parse %s", jsonfile);
195
196                         var pa = new Json.Parser();
197                         pa.load_from_file(jsonfile);
198                         var node = pa.get_root();
199
200                         
201                         if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
202                                 GLib.debug("SKIP " + jsonfile + " - invalid format?");
203                                 return;
204                         }
205                         
206                         var obj = node.get_object ();
207                         var xtype =  obj.get_string_member("xtype");
208
209
210                         var paths = obj.get_object_member("paths");
211                         var i = 0;
212                         var fpath = "";
213                         paths.foreach_member((sobj, key, val) => {
214                                 if (i ==0 ) {
215                                         fpath = key;
216                                 }
217                                         
218                         });
219
220                         
221                         var proj = factory(xtype, fpath);
222
223                         proj.json_project_data  = obj; // store the original object...
224                         
225                         proj.fn =  Path.get_basename(jsonfile).split(".")[0];
226
227                         // might not exist?
228
229                         if (obj.has_member("runhtml")) {
230                                         proj.runhtml  = obj.get_string_member("runhtml"); 
231                         }
232                         // might not exist?
233                         if (obj.has_member("base_template")) {
234                                         proj.base_template  = obj.get_string_member("base_template"); 
235                         }
236                         // might not exist?
237                         if (obj.has_member("rootURL")) {
238                                         proj.rootURL  = obj.get_string_member("rootURL"); 
239                         }
240                         
241                         proj.name = obj.get_string_member("name");
242
243                          
244                         paths.foreach_member((sobj, key, val) => {
245                                 proj.paths.set(key, "dir");
246                         });
247                         proj.initRooDatabase();
248                         
249                         GLib.debug("Add Project %s", proj.id);
250                         
251                         projects.set(proj.id,proj);
252                         
253                         
254                         
255                         
256                 }
257                 
258                 
259                 public static Project factory(string xtype, string path)
260                 {
261
262                         // check to see if it's already loaded..
263
264                          
265                         var iter = projects.map_iterator();
266                         while (iter.next()) {
267                                 if (iter.get_value().hasPath( path)) {
268                                         return iter.get_value();
269                                  }
270                         }
271
272
273                         switch(xtype) {
274                                 case "Gtk":
275                                         return new Gtk(path);
276                                 case "Roo":
277                                         return new Roo(path);
278                         }
279                         throw new Error.INVALID_TYPE("invalid project type");
280                                 
281                 }
282                 
283                 
284                 
285                  public static void  remove(Project project)
286                 {
287                         // delete the file..
288                         var dirname = GLib.Environment.get_home_dir() + "/.Builder";
289                                  
290                         FileUtils.unlink(dirname + "/" + project.fn + ".json");
291                         projects.unset(project.id,null);
292                         
293
294                 }
295                  
296
297                 public void save()
298                 {
299                                 // fixme..
300                         
301                         if (this.fn.length < 1) {
302                                 // make the filename..
303                                 //var t = new DateTime.now_local ();
304                                 //TimeVal tv;
305                                 //t.to_timeval(out tv);
306                                 //var str = "%l:%l".printf(tv.tv_sec,tv.tv_usec);
307                                 var str = this.firstPath();
308                                 
309                                         this.fn = GLib.Checksum.compute_for_string(GLib.ChecksumType.MD5, str, str.length);
310                         }
311
312                         var dirname = GLib.Environment.get_home_dir() + "/.Builder";
313                         var  s =  this.toJSON(false);
314                         FileUtils.set_contents(dirname + "/" + this.fn + ".json", s, s.length);  
315                         
316                         
317                 }
318
319                 
320                 
321                 public string toJSON(bool show_all)
322                 {
323                         
324                         
325                         this.json_project_data.set_string_member("name", this.name);
326                         this.json_project_data.set_string_member("fn", this.fn);
327                         this.json_project_data.set_string_member("xtype", this.xtype);
328                         this.json_project_data.set_string_member("runhtml", this.runhtml);
329                         this.json_project_data.set_string_member("rootURL", this.rootURL);
330                         this.json_project_data.set_string_member("base_template", this.base_template);
331                         this.json_project_data.set_string_member("rootURL", this.rootURL);
332  
333                         var paths = new Json.Object(); 
334
335
336                         var iter = this.paths.map_iterator();
337                         while (iter.next()) {
338                                 paths.set_string_member(iter.get_key(), "path");
339                         }
340                         this.json_project_data.set_object_member("paths", paths);
341
342                         
343                         if (show_all) {
344                                 var files = new Json.Array();
345                                 
346                                 
347                                 var fiter = this.files.map_iterator();
348                                 while (fiter.next()) {
349                                         files.add_string_element (fiter.get_key());
350                                 }
351                                 this.json_project_data.set_array_member("files", files);
352                                 
353                         }
354
355                 
356                         var  generator = new Json.Generator ();
357                         var  root = new Json.Node(Json.NodeType.OBJECT);
358                         root.init_object(this.json_project_data);
359                         generator.set_root (root);
360                         if (show_all) {
361                                 generator.pretty = true;
362                                 generator.indent = 4;
363                         }
364
365                         return  generator.to_data (null);
366                           
367                           
368                 }
369                 public string firstPath()
370                 {
371                         var iter = this.paths.map_iterator();
372                         while (iter.next()) {
373                                 return iter.get_key();
374                         }
375                   
376                         return "";
377                 }
378
379                 public bool hasPath(string path)
380                 {
381                         var iter = this.paths.map_iterator();
382                         while (iter.next()) {
383                                 if (iter.get_key() == path) {
384                                 return true;
385                         }
386                         }
387                   
388                         return false;
389                 }
390
391                 
392                 // returns the first path
393                 public string getName()
394                 {
395                         var iter = this.paths.map_iterator();
396                         while (iter.next()) {
397                                 return GLib.Path.get_basename(iter.get_key());
398                         }
399                   
400                         return "";
401                 }
402
403                 public Gee.ArrayList<JsRender.JsRender> sortedFiles()
404                 {
405                         var files = new Gee.ArrayList<JsRender.JsRender>();
406
407                         var fiter = this.files.map_iterator();
408                         while(fiter.next()) {
409                                 files.add(fiter.get_value());
410                         }
411                         files.sort((fa,fb) => {
412                                 return ((JsRender.JsRender)fa).name.collate(((JsRender.JsRender)fb).name);
413
414                         });
415                         return files;
416
417                 }
418                 
419          
420          
421                 public string listAllFilesToString()
422                 {
423                         this.scanDirs();
424                         var iter = this.sortedFiles().list_iterator();
425                         var ret = "ID\tName\tDirectory\n";
426                         while (iter.next()) {
427                                 ret += "%s\n".printf(
428                                                  
429                                                 iter.get().name
430                                                  
431                                                 );
432                          
433                                 
434                         }
435                         
436                         return ret;
437                 
438                 }
439                 
440          
441          
442          
443                 public JsRender.JsRender? getByName(string name)
444                 {
445                         
446                         var fiter = files.map_iterator();
447                         while(fiter.next()) {
448                          
449                                 var f = fiter.get_value();
450                                 
451                                 
452                                 GLib.debug ("Project.getByName: %s ?= %s" ,f.name , name);
453                                 if (f.name == name) {
454                                         return f;
455                                 }
456                         };
457                         return null;
458                 }
459                 public JsRender.JsRender? getByPath(string path)
460                 {
461                         
462                         var fiter = files.map_iterator();
463                         while(fiter.next()) {
464                          
465                                 var f = fiter.get_value();
466                                 
467                                 
468                                 //GLib.debug ("Project.getByName: %s ?= %s" ,f.name , name);
469                                 if (f.path == path) {
470                                         return f;
471                                 }
472                         };
473                         return null;
474                 }
475                 
476                 public JsRender.JsRender? getById(string id)
477                 {
478                         
479                         var fiter = files.map_iterator();
480                         while(fiter.next()) {
481                          
482                                 var f = fiter.get_value();
483                                 
484                                 
485                                 //console.log(f.id + '?=' + id);
486                                 if (f.id == id) {
487                                         return f;
488                                 }
489                                 };
490                         return null;
491                 }
492
493                 public JsRender.JsRender newFile (string name)
494                 {
495                         var ret =  JsRender.JsRender.factory(this.xtype, 
496                                                                                          this, 
497                                                                                          this.firstPath() + "/" + name + ".bjs");
498                         this.addFile(ret);
499                         return ret;
500                 }
501                 
502                 public JsRender.JsRender loadFileOnly (string path)
503                 {
504                         var xt = this.xtype;
505                         return JsRender.JsRender.factory(xt, this, path);
506                         
507                 }
508                 
509                 public JsRender.JsRender create(string filename)
510                 {
511                         var ret = this.loadFileOnly(filename);
512                         ret.save();
513                         this.addFile(ret);
514                         return ret;
515                         
516                 }
517                         
518                          
519                 public void addFile(JsRender.JsRender pfile) { // add a single file, and trigger changed.
520                 
521                 
522                         this.files.set(pfile.path, pfile); // duplicate check?
523                         this.on_changed();
524                 }
525                 
526                 public void add(string path, string type)
527                 {
528                         this.paths.set(path,type);
529                         //Seed.print(" type is '" + type + "'");
530                         if (type == "dir") {
531                                 this.scanDir(path);
532                         //    console.dump(this.files);
533                         }
534                         if (type == "file" ) {
535                         
536                                 this.files.set(path,this.loadFileOnly( path ));
537                         }
538                         this.on_changed();
539                         
540                 }
541                 public void  scanDirs() // cached version
542                 {
543                         if (this.is_scanned) {
544                                 return;
545                         }
546                         this.scanDirsForce();
547                         //console.dump(this.files);
548                         
549                 }
550                 
551                 public void  scanDirsForce()
552                 {
553                         this.is_scanned = true;  
554                         var iter = this.paths.map_iterator();
555                         while (iter.next()) {
556                                 //print("path: " + iter.get_key() + " : " + iter.get_value() +"\n");
557                                 if (iter.get_value() != "dir") {
558                                         continue;
559                                 }
560                                 this.scanDir(iter.get_key());
561                         }
562                         //console.dump(this.files);
563                         
564                 }
565                         // list files.
566                 public void scanDir(string dir, int dp =0 ) 
567                 {
568                         //dp = dp || 0;
569                         //print("Project.Base: Running scandir on " + dir +"\n");
570                         if (dp > 5) { // no more than 5 deep?
571                                 return;
572                         }
573                         // this should be done async -- but since we are getting the proto up ...
574                         
575                         var subs = new GLib.List<string>();;            
576                         var f = File.new_for_path(dir);
577                         try {
578                                 var file_enum = f.enumerate_children(GLib.FileAttribute.STANDARD_DISPLAY_NAME, GLib.FileQueryInfoFlags.NONE, null);
579                                 
580                                  
581                                 FileInfo next_file; 
582                                 while ((next_file = file_enum.next_file(null)) != null) {
583                                         var fn = next_file.get_display_name();
584                         
585                                          
586                                         //print("trying"  + dir + "/" + fn +"\n");
587                                         
588                                         if (fn[0] == '.') { // skip hidden
589                                                 continue;
590                                         }
591                                         
592                                         if (FileUtils.test(dir  + "/" + fn, GLib.FileTest.IS_DIR)) {
593                                                 subs.append(dir  + "/" + fn);
594                                                 continue;
595                                         }
596                                         
597                                         if (!Regex.match_simple("\\.bjs$", fn)) {
598                                                 //print("no a bjs\n");
599                                                 continue;
600                                         }
601                                         /*
602                                         var parent = "";
603                                         //if (dp > 0 ) {
604                                         
605                                         var sp = dir.split("/");
606                                         var parent = "";
607                                         for (var i = 0; i < sp.length; i++) {
608                                                 
609                                         }
610                                         
611                                         /*
612                                         sp = sp.splice(sp.length - (dp +1), (dp +1));
613                                         parent = sp.join('.');
614                                         
615                                         
616                                         if (typeof(_this.files[dir  + '/' + fn]) != 'undefined') {
617                                                 // we already have it..
618                                                 _this.files[dir  + '/' + fn].parent = parent;
619                                                 return;
620                                         }
621                                         */
622                                         var xt = this.xtype;
623                                         var el = JsRender.JsRender.factory(xt,this, dir + "/" + fn);
624                                         this.files.set( dir + "/" + fn, el);
625                                         // parent ?? 
626                                         
627                                          
628                                 }
629                         } catch (Error e) {
630                                 GLib.warning("Project::scanDirs failed : " + e.message + "\n");
631                         } catch (GLib.Error e) {
632                                 GLib.warning("Project::scanDirs failed : " + e.message + "\n");
633                         }
634                         for (var i = 0; i < subs.length(); i++) {
635                                 
636                                  this.scanDir(subs.nth_data(i), dp+1);
637                         }
638                         
639                 }
640                 // wrapper around the javascript data...
641                 public string get_string_member(string key) {
642                         
643                         if (!this.json_project_data.has_member(key)) {
644                                 return "";
645                         }
646                         var  ret = this.json_project_data.get_string_member(key);
647                         if (ret == null) {
648                                 return "";
649                         }
650                         return ret;
651                         
652                 }
653                   
654         }
655 }
656