978d877afd49b42bd719ede6ca01f2fe75a3211f
[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                         
145                         var iter = projects.map_iterator();
146                         var ret = "ID\tName\tDirectory\n";
147                         while (iter.next()) {
148                                 ret += "%s\t%s\t%s\n".printf(
149                                                 iter.get_value().id,
150                                                 iter.get_value().name,
151                                                 iter.get_value().firstPath()
152                                                 );
153                                 }
154                                 
155                         }
156                         
157                         return ret;
158                 
159                 }
160                 
161                 
162                 
163                 public static Project getProjectByHash(string fn)
164                 {
165                         
166                         var iter = projects.map_iterator();
167                         while (iter.next()) {
168                                 if (iter.get_value().fn == fn) {
169                                         return iter.get_value();
170                                 }
171                                 
172                         }
173                         
174                         return null;
175                 
176                 }
177                 
178                 // load project data from project file.
179                 public static void   factoryFromFile(string jsonfile)
180                 {
181                          
182                         GLib.debug("parse %s", jsonfile);
183
184                         var pa = new Json.Parser();
185                         pa.load_from_file(jsonfile);
186                         var node = pa.get_root();
187
188                         
189                         if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
190                                 GLib.debug("SKIP " + jsonfile + " - invalid format?");
191                                 return;
192                         }
193                         
194                         var obj = node.get_object ();
195                         var xtype =  obj.get_string_member("xtype");
196
197
198                         var paths = obj.get_object_member("paths");
199                         var i = 0;
200                         var fpath = "";
201                         paths.foreach_member((sobj, key, val) => {
202                                 if (i ==0 ) {
203                                         fpath = key;
204                                 }
205                                         
206                         });
207
208                         
209                         var proj = factory(xtype, fpath);
210
211                         proj.json_project_data  = obj; // store the original object...
212                         
213                         proj.fn =  Path.get_basename(jsonfile).split(".")[0];
214
215                         // might not exist?
216
217                         if (obj.has_member("runhtml")) {
218                                         proj.runhtml  = obj.get_string_member("runhtml"); 
219                         }
220                         // might not exist?
221                         if (obj.has_member("base_template")) {
222                                         proj.base_template  = obj.get_string_member("base_template"); 
223                         }
224                         // might not exist?
225                         if (obj.has_member("rootURL")) {
226                                         proj.rootURL  = obj.get_string_member("rootURL"); 
227                         }
228                         
229                         proj.name = obj.get_string_member("name");
230
231                          
232                         paths.foreach_member((sobj, key, val) => {
233                                 proj.paths.set(key, "dir");
234                         });
235                         proj.initRooDatabase();
236                         
237                         GLib.debug("Add Project %s", proj.id);
238                         
239                         projects.set(proj.id,proj);
240                         
241                         
242                         
243                         
244                 }
245                 
246                 
247                 public static Project factory(string xtype, string path)
248                 {
249
250                         // check to see if it's already loaded..
251
252                          
253                         var iter = projects.map_iterator();
254                         while (iter.next()) {
255                                 if (iter.get_value().hasPath( path)) {
256                                         return iter.get_value();
257                                  }
258                         }
259
260
261                         switch(xtype) {
262                                 case "Gtk":
263                                         return new Gtk(path);
264                                 case "Roo":
265                                         return new Roo(path);
266                         }
267                         throw new Error.INVALID_TYPE("invalid project type");
268                                 
269                 }
270                 
271                 
272                 
273                  public static void  remove(Project project)
274                 {
275                         // delete the file..
276                         var dirname = GLib.Environment.get_home_dir() + "/.Builder";
277                                  
278                         FileUtils.unlink(dirname + "/" + project.fn + ".json");
279                         projects.unset(project.id,null);
280                         
281
282                 }
283                  
284
285                 public void save()
286                 {
287                                 // fixme..
288                         
289                         if (this.fn.length < 1) {
290                                 // make the filename..
291                                 //var t = new DateTime.now_local ();
292                                 //TimeVal tv;
293                                 //t.to_timeval(out tv);
294                                 //var str = "%l:%l".printf(tv.tv_sec,tv.tv_usec);
295                                 var str = this.firstPath();
296                                 
297                                         this.fn = GLib.Checksum.compute_for_string(GLib.ChecksumType.MD5, str, str.length);
298                         }
299
300                         var dirname = GLib.Environment.get_home_dir() + "/.Builder";
301                         var  s =  this.toJSON(false);
302                         FileUtils.set_contents(dirname + "/" + this.fn + ".json", s, s.length);  
303                         
304                         
305                 }
306
307                 
308                 
309                 public string toJSON(bool show_all)
310                 {
311                         
312                         
313                         this.json_project_data.set_string_member("name", this.name);
314                         this.json_project_data.set_string_member("fn", this.fn);
315                         this.json_project_data.set_string_member("xtype", this.xtype);
316                         this.json_project_data.set_string_member("runhtml", this.runhtml);
317                         this.json_project_data.set_string_member("rootURL", this.rootURL);
318                         this.json_project_data.set_string_member("base_template", this.base_template);
319                         this.json_project_data.set_string_member("rootURL", this.rootURL);
320  
321                         var paths = new Json.Object(); 
322
323
324                         var iter = this.paths.map_iterator();
325                         while (iter.next()) {
326                                 paths.set_string_member(iter.get_key(), "path");
327                         }
328                         this.json_project_data.set_object_member("paths", paths);
329
330                         
331                         if (show_all) {
332                                 var files = new Json.Array();
333                                 
334                                 
335                                 var fiter = this.files.map_iterator();
336                                 while (fiter.next()) {
337                                         files.add_string_element (fiter.get_key());
338                                 }
339                                 this.json_project_data.set_array_member("files", files);
340                                 
341                         }
342
343                 
344                         var  generator = new Json.Generator ();
345                         var  root = new Json.Node(Json.NodeType.OBJECT);
346                         root.init_object(this.json_project_data);
347                         generator.set_root (root);
348                         if (show_all) {
349                                 generator.pretty = true;
350                                 generator.indent = 4;
351                         }
352
353                         return  generator.to_data (null);
354                           
355                           
356                 }
357                 public string firstPath()
358                 {
359                         var iter = this.paths.map_iterator();
360                         while (iter.next()) {
361                                 return iter.get_key();
362                         }
363                   
364                         return "";
365                 }
366
367                 public bool hasPath(string path)
368                 {
369                         var iter = this.paths.map_iterator();
370                         while (iter.next()) {
371                                 if (iter.get_key() == path) {
372                                 return true;
373                         }
374                         }
375                   
376                         return false;
377                 }
378
379                 
380                 // returns the first path
381                 public string getName()
382                 {
383                         var iter = this.paths.map_iterator();
384                         while (iter.next()) {
385                                 return GLib.Path.get_basename(iter.get_key());
386                         }
387                   
388                         return "";
389                 }
390
391                 public Gee.ArrayList<JsRender.JsRender> sortedFiles()
392                 {
393                         var files = new Gee.ArrayList<JsRender.JsRender>();
394
395                         var fiter = this.files.map_iterator();
396                         while(fiter.next()) {
397                                 files.add(fiter.get_value());
398                         }
399                         files.sort((fa,fb) => {
400                                 return ((JsRender.JsRender)fa).name.collate(((JsRender.JsRender)fb).name);
401
402                         });
403                         return files;
404
405                 }
406                 
407          
408                 public JsRender.JsRender? getByName(string name)
409                 {
410                         
411                         var fiter = files.map_iterator();
412                         while(fiter.next()) {
413                          
414                                 var f = fiter.get_value();
415                                 
416                                 
417                                 GLib.debug ("Project.getByName: %s ?= %s" ,f.name , name);
418                                 if (f.name == name) {
419                                         return f;
420                                 }
421                         };
422                         return null;
423                 }
424                 public JsRender.JsRender? getByPath(string path)
425                 {
426                         
427                         var fiter = files.map_iterator();
428                         while(fiter.next()) {
429                          
430                                 var f = fiter.get_value();
431                                 
432                                 
433                                 //GLib.debug ("Project.getByName: %s ?= %s" ,f.name , name);
434                                 if (f.path == path) {
435                                         return f;
436                                 }
437                         };
438                         return null;
439                 }
440                 
441                 public JsRender.JsRender? getById(string id)
442                 {
443                         
444                         var fiter = files.map_iterator();
445                         while(fiter.next()) {
446                          
447                                 var f = fiter.get_value();
448                                 
449                                 
450                                 //console.log(f.id + '?=' + id);
451                                 if (f.id == id) {
452                                         return f;
453                                 }
454                                 };
455                         return null;
456                 }
457
458                 public JsRender.JsRender newFile (string name)
459                 {
460                         var ret =  JsRender.JsRender.factory(this.xtype, 
461                                                                                          this, 
462                                                                                          this.firstPath() + "/" + name + ".bjs");
463                         this.addFile(ret);
464                         return ret;
465                 }
466                 
467                 public JsRender.JsRender loadFileOnly (string path)
468                 {
469                         var xt = this.xtype;
470                         return JsRender.JsRender.factory(xt, this, path);
471                         
472                 }
473                 
474                 public JsRender.JsRender create(string filename)
475                 {
476                         var ret = this.loadFileOnly(filename);
477                         ret.save();
478                         this.addFile(ret);
479                         return ret;
480                         
481                 }
482                         
483                          
484                 public void addFile(JsRender.JsRender pfile) { // add a single file, and trigger changed.
485                 
486                 
487                         this.files.set(pfile.path, pfile); // duplicate check?
488                         this.on_changed();
489                 }
490                 
491                 public void add(string path, string type)
492                 {
493                         this.paths.set(path,type);
494                         //Seed.print(" type is '" + type + "'");
495                         if (type == "dir") {
496                                 this.scanDir(path);
497                         //    console.dump(this.files);
498                         }
499                         if (type == "file" ) {
500                         
501                                 this.files.set(path,this.loadFileOnly( path ));
502                         }
503                         this.on_changed();
504                         
505                 }
506                 public void  scanDirs() // cached version
507                 {
508                         if (this.is_scanned) {
509                                 return;
510                         }
511                         this.scanDirsForce();
512                         //console.dump(this.files);
513                         
514                 }
515                 
516                 public void  scanDirsForce()
517                 {
518                         this.is_scanned = true;  
519                         var iter = this.paths.map_iterator();
520                         while (iter.next()) {
521                                 //print("path: " + iter.get_key() + " : " + iter.get_value() +"\n");
522                                 if (iter.get_value() != "dir") {
523                                         continue;
524                                 }
525                                 this.scanDir(iter.get_key());
526                         }
527                         //console.dump(this.files);
528                         
529                 }
530                         // list files.
531                 public void scanDir(string dir, int dp =0 ) 
532                 {
533                         //dp = dp || 0;
534                         //print("Project.Base: Running scandir on " + dir +"\n");
535                         if (dp > 5) { // no more than 5 deep?
536                                 return;
537                         }
538                         // this should be done async -- but since we are getting the proto up ...
539                         
540                         var subs = new GLib.List<string>();;            
541                         var f = File.new_for_path(dir);
542                         try {
543                                 var file_enum = f.enumerate_children(GLib.FileAttribute.STANDARD_DISPLAY_NAME, GLib.FileQueryInfoFlags.NONE, null);
544                                 
545                                  
546                                 FileInfo next_file; 
547                                 while ((next_file = file_enum.next_file(null)) != null) {
548                                         var fn = next_file.get_display_name();
549                         
550                                          
551                                         //print("trying"  + dir + "/" + fn +"\n");
552                                         
553                                         if (fn[0] == '.') { // skip hidden
554                                                 continue;
555                                         }
556                                         
557                                         if (FileUtils.test(dir  + "/" + fn, GLib.FileTest.IS_DIR)) {
558                                                 subs.append(dir  + "/" + fn);
559                                                 continue;
560                                         }
561                                         
562                                         if (!Regex.match_simple("\\.bjs$", fn)) {
563                                                 //print("no a bjs\n");
564                                                 continue;
565                                         }
566                                         /*
567                                         var parent = "";
568                                         //if (dp > 0 ) {
569                                         
570                                         var sp = dir.split("/");
571                                         var parent = "";
572                                         for (var i = 0; i < sp.length; i++) {
573                                                 
574                                         }
575                                         
576                                         /*
577                                         sp = sp.splice(sp.length - (dp +1), (dp +1));
578                                         parent = sp.join('.');
579                                         
580                                         
581                                         if (typeof(_this.files[dir  + '/' + fn]) != 'undefined') {
582                                                 // we already have it..
583                                                 _this.files[dir  + '/' + fn].parent = parent;
584                                                 return;
585                                         }
586                                         */
587                                         var xt = this.xtype;
588                                         var el = JsRender.JsRender.factory(xt,this, dir + "/" + fn);
589                                         this.files.set( dir + "/" + fn, el);
590                                         // parent ?? 
591                                         
592                                          
593                                 }
594                         } catch (Error e) {
595                                 GLib.warning("Project::scanDirs failed : " + e.message + "\n");
596                         } catch (GLib.Error e) {
597                                 GLib.warning("Project::scanDirs failed : " + e.message + "\n");
598                         }
599                         for (var i = 0; i < subs.length(); i++) {
600                                 
601                                  this.scanDir(subs.nth_data(i), dp+1);
602                         }
603                         
604                 }
605                 // wrapper around the javascript data...
606                 public string get_string_member(string key) {
607                         
608                         if (!this.json_project_data.has_member(key)) {
609                                 return "";
610                         }
611                         var  ret = this.json_project_data.get_string_member(key);
612                         if (ret == null) {
613                                 return "";
614                         }
615                         return ret;
616                         
617                 }
618                   
619         }
620 }
621