Fix #7959 - new project flow - use void func to callback after each step, tidy up...
[roobuilder] / 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  * currently we store projects in ~/.Builder/{md5}.json
11    - then for Gtk projects we have a file config1.builder - which contains dependancies, and a list of files for each target
12      (for builder it's ended up in src/Builder/config1.builder? by accident.
13    - should really support something like 
14        roobuilder --build {path_to_cfg} {target} - or local directory if not set..
15        roobuilder --build-errors {path_to_cfg} {target} - or local directory if not set..
16        
17        
18    
19    
20    should really store project data in the directory of the project?
21    
22    
23    // steps:
24    // List of projects - just an array of paths in .Builder/Projects.json
25    
26    // .roobuilder.jcfg  << hidden file with project details?
27    
28    
29    
30  
31  * 
32  * 
33  */
34 namespace Project {
35          public errordomain Error {
36                 INVALID_TYPE,
37                 NEED_IMPLEMENTING,
38                 MISSING_FILE,
39                 INVALID_VALUE,
40                 INVALID_FORMAT
41         }
42
43
44         
45         // static array of all projects.
46         private Gee.ArrayList<Project>  projects;
47         
48         
49         
50         public bool  projects_loaded = false;
51         
52         
53         // used to pass around callbacks with project as a return
54         public class Callback : Object {
55                 public signal void call(Project project);
56         }
57         
58         public abstract class Project : Object {
59                 
60                 public signal void on_changed (); 
61         
62                 //public string id;
63                 //public string fn = ""; // just a md5...
64                 public string name  { 
65                         private set {} 
66                         owned get {
67                                 return GLib.Path.get_basename(path);
68                         }
69                          
70                 }
71                                 
72                 
73                 public string path = "";
74                 private Gee.ArrayList<JsRender.JsRender> sub_paths;
75                 
76                 private Gee.HashMap<string,JsRender.JsRender> files ;  // contains full list of files.
77                 //tree : false,
78                 public  string xtype;
79                 
80                 //public Json.Object json_project_data;
81
82                 public Palete.Palete palete;
83                  
84                 private bool is_scanned = false; 
85                 public  Gee.HashMap<string,Palete.GirObject> gir_cache = null; // used by Gir ??? is this used by Roo?
86                  public Palete.ValaCompileRequest last_request = null;
87                 
88                 protected Project (string path) {
89                         
90                          
91                         //this.json_project_data = new Json.Object();
92                         
93                         this.is_scanned = false;
94                         this.sub_paths = new Gee.ArrayList<JsRender.JsRender>();
95                         this.files = new Gee.HashMap<string,JsRender.JsRender>();
96                         //XObject.extend(this, cfg);
97                         //this.files = { }; 
98                         this.path = path;
99                          
100                         
101                         
102                 }
103                  
104                 
105                 
106                 
107                 public static void loadAll(bool force = false)
108                 {
109                         if (projects_loaded && !force) {
110                                 return;
111                         }
112
113                         var dirname = GLib.Environment.get_home_dir() + "/.Builder";
114                         var dir = File.new_for_path(dirname);
115                         if (!dir.query_exists()) {
116                                 try {
117                                         dir.make_directory();
118                                 } catch(GLib.Error e) {
119                                         GLib.error("could not make builder directory");
120                                 }
121                                 return;
122                         }
123                         projects = new  Gee.ArrayList<Project>();
124                           
125                     
126                     if (FileUtils.test(dirname + "/Projects.list", GLib.FileTest.IS_REGULAR)) {
127                         loadProjectList();
128                         projects_loaded = true;
129                         return;
130                 }
131                 convertOldProjects(); // this saves..
132                 foreach(var p in projects) {
133                         p.save();
134                 }
135                         projects_loaded = true;
136  
137         }
138          
139         public static void remove(Project p) {
140                 projects.remove(p);
141                 saveProjectList();
142         
143         }
144         
145         public static void saveProjectList()
146         {
147                         var f = new Json.Object();
148                         foreach(var p in projects) {
149                                 f.set_string_member(p.path, p.xtype);
150                         }
151                         
152                         var  generator = new Json.Generator ();
153                         var  root = new Json.Node(Json.NodeType.OBJECT);
154                         root.init_object(f);
155                         generator.set_root (root);
156                         generator.pretty = true;
157                         generator.indent = 4;
158
159                         var data = generator.to_data (null);
160                         var dirname = GLib.Environment.get_home_dir() + "/.Builder";
161                 GLib.debug("Write new Project list\n %s", data);
162                 //Posix.exit(0);
163                 
164                 try {
165                                 //FileUtils.set_contents(dirname + "/" + this.fn + ".json", s, s.length);  
166                                 FileUtils.set_contents(dirname + "/Projects.list", data, data.length);  
167                         } catch (GLib.Error e) {
168                                 GLib.error("failed  to save file %s", e.message);
169                         }
170                 
171         }
172         
173         
174         
175         public static void convertOldProjects()
176         {
177         
178                         var dirname = GLib.Environment.get_home_dir() + "/.Builder";
179                         var  dir = File.new_for_path(dirname);
180                         try {
181                                 var file_enum = dir.enumerate_children(
182                                                                 GLib.FileAttribute.STANDARD_DISPLAY_NAME, 
183                                         GLib.FileQueryInfoFlags.NONE, 
184                                         null
185                                 );
186                                  
187                                 FileInfo next_file; 
188                                 while ((next_file = file_enum.next_file(null)) != null) {
189                                         var fn = next_file.get_display_name();
190                                         if (!Regex.match_simple("\\.json$", fn)) {
191                                                 continue;
192                                         }
193                                         Project.factoryFromFileOld(dirname + "/" + fn);
194                                 }       
195                         } catch(GLib.Error e) {
196                                 GLib.warning("oops - something went wrong scanning the projects\n");
197                         }
198                         GLib.debug("Loaded all old Projects - saving");
199                         Project.saveProjectList();
200
201                 }
202
203                 public static Gee.ArrayList<Project> allProjectsByName()
204                 {
205                         
206                         return projects;
207                 
208                 }
209                 
210                 public static Project? getProjectByName(string name)
211                 {
212                         
213                         foreach (var p in projects) {
214                                 if (p.name == name) {
215                                         return p;
216                                 }
217                         }
218                         
219                         return null;
220                 
221                 }
222                 public static Project? getProjectByPath(string path)
223                 {
224                         
225                         foreach (var p in projects) {
226                                 if (p.path == path) {
227                                         return p;
228                                 }
229                         }
230                         
231                         return null;
232                 
233                 }
234                 public static string listAllToString()
235                 {
236                         var all = projects;
237
238                          
239                         
240                         all.sort((fa,fb) => {
241                                 return ((Project)fa).name.collate(((Project)fb).name);
242
243                         });
244
245                         var iter = all.list_iterator();
246                         var ret = "ID\tName\tDirectory\n";
247                         while (iter.next()) {
248                                 ret += "%s\t%s\n".printf(
249                                                  
250                                                 iter.get().name,
251                                                 iter.get().path
252                                                 );
253                          
254                                 
255                         }
256                         
257                         return ret;
258                 
259                 }
260                 
261                 
262                 public static void loadIntoStore(GLib.ListStore st)
263                 {
264                         st.remove_all();
265                         foreach (var p in projects) {
266                                 st.append(p);
267                         }
268                         
269                 }
270                         
271                 
272  
273                 
274                 static void loadProjectList()
275                 {
276                 
277                         var dirname = GLib.Environment.get_home_dir() + "/.Builder";
278                          
279                         projects = new  Gee.ArrayList<Project>();
280                           
281                     var pa = new Json.Parser();
282                         try { 
283                                 pa.load_from_file(dirname + "/Projects.list");  
284                         } catch (GLib.Error e) {
285                                 GLib.error("could not load json file %s", e.message);
286                         }
287                         var node = pa.get_root();
288                         if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
289                                 GLib.error( dirname + "/Projects.list - invalid format?");
290                                  
291                         }
292
293                         
294                         var obj = node.get_object ();
295                         obj.foreach_member((sobj, key, val) => {
296                                 GLib.debug("read ProjectList %s: %s", key, val.get_string());
297                                 // facotry adds project!
298                                 try {
299                                         Project.factory(val.get_string(), key );
300                                 } catch (GLib.Error e ) {
301                                         GLib.debug("error createing project %s", e.message);
302                                 }
303                                  
304                         });
305                         
306                 
307                 }
308                 
309                 // load project data from project file.
310                 public static void   factoryFromFileOld(string jsonfile)
311                 {
312                          
313                         GLib.debug("parse %s", jsonfile);
314
315                         var pa = new Json.Parser();
316                         try { 
317                                 pa.load_from_file(jsonfile);
318                         } catch (GLib.Error e) {
319                                 GLib.error("could not load json file %s", e.message);
320                         }
321                         var node = pa.get_root();
322
323                         
324                         if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
325                                 GLib.debug("SKIP " + jsonfile + " - invalid format?");
326                                 return;
327                         }
328                         
329                         var obj = node.get_object ();
330                         var xtype =  obj.get_string_member("xtype");
331
332
333                         var paths = obj.get_object_member("paths");
334                         var i = 0;
335                         var fpath = "";
336                         paths.foreach_member((sobj, key, val) => {
337                                 if (i ==0 ) {
338                                         fpath = key;
339                                 }
340                                         
341                         });
342                         
343                         if (fpath.length < 0 || !FileUtils.test(fpath,FileTest.IS_DIR)) {
344                                 return;
345                         }
346                         
347                         Project proj;
348                         try {
349                                 proj = factory(xtype, fpath);
350                         } catch (Error e)  {
351                                 GLib.debug("Skip file - invalid file type");
352                                 return;
353                         }
354
355                         //proj.json_project_data  = obj; // store the original object...
356                         
357                         //proj.fn =  Path.get_basename(jsonfile).split(".")[0];
358
359                         proj.loadJson(obj);
360                         // might not exist?
361  
362                         proj.name = obj.get_string_member("name");
363
364                         // used to load paths..
365                         //proj.initSubDirectories();
366                         
367                          
368                         //proj.initDatabase();
369                         
370                         GLib.debug("Add Project %s", proj.name);
371                         
372                         projects.add(proj);
373                          
374                         
375                 }
376                 
377                 
378                 public static Project factory(string xtype, string path) throws Error
379                 {
380
381                         // check to see if it's already loaded..
382
383                          foreach(var p in projects) {
384                                   if (p.path == path) {
385                                         return p;
386                                  }
387                         }
388
389                         
390                         switch(xtype) {
391                                 case "Gtk":
392                                         var ret =  new Gtk(path);
393                                         projects.add(ret);
394                                         
395                                         return ret;
396                                 case "Roo":
397                                         var ret = new Roo(path);
398                                         projects.add(ret);
399                                  
400                                         return ret;
401                                 //case "Flutter":
402                                 //      return new Flutter(path);
403                         }
404                         throw new Error.INVALID_TYPE("invalid project type");
405                                 
406                 }
407                 
408                 
409          
410
411                 public void save()
412                 {
413                                 // fixme..
414                         
415                  
416
417                         
418
419                         //var dirname = GLib.Environment.get_home_dir() + "/.Builder";
420                         
421                         var  s =  this.toJSON();
422                         GLib.debug("Save Project %s\n%s", this.name, s);
423                         try {
424                                 //FileUtils.set_contents(dirname + "/" + this.fn + ".json", s, s.length);  
425                                 FileUtils.set_contents(this.path + "/.roobuilder.jcfg", s, s.length);  
426                         } catch (GLib.Error e) {
427                                 GLib.error("failed  to save file %s", e.message);
428                         }
429                         
430                 }
431
432         
433                 
434                 
435                 public string toJSON( )
436                 {
437                         
438                         var obj = new Json.Object();
439                         obj.set_string_member("xtype", this.xtype);
440                                                 
441                         
442                         this.saveJson(obj);
443                 
444                         var  generator = new Json.Generator ();
445                         var  root = new Json.Node(Json.NodeType.OBJECT);
446                         root.init_object(obj);
447                         generator.set_root (root);
448                         //if (show_all) {
449                                 generator.pretty = true;
450                                 generator.indent = 4;
451                         //}
452
453                         return  generator.to_data (null);
454                           
455                           
456                 }
457                 
458                 // used to check what type a project might be..
459                 // for 'new'
460                 public static string peekProjectType(string fn) 
461                 {
462                         var pa = new Json.Parser();
463                         try { 
464                                 pa.load_from_file(fn);
465                         } catch (GLib.Error e) {
466                                 GLib.debug("could not load json file %s", e.message);
467                                 return "";
468                                 
469                         }
470                         var node = pa.get_root();
471
472                         if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
473                                 GLib.debug("SKIP %s/.roobuilder.jcfg  - invalid format?",fn);
474                                 return "";
475                         }
476                         
477                         var obj = node.get_object ();
478
479                         var xtype =  obj.get_string_member("xtype");
480                         return xtype == null ? "" : xtype;
481                 
482                 }
483                 
484                 
485                 // this will do a full scan - should only be done on viewing project..
486                 // not initial load.. - may take time.
487                 
488                 public   void   load()
489                 {
490                         if (this.is_scanned) {
491                                 return;
492                         }
493                         GLib.debug("load is_scanned = false");
494                         
495                         if (FileUtils.test(this.path + "/.roobuilder.jcfg", FileTest.EXISTS)) {
496                                   
497                                 var pa = new Json.Parser();
498                                 try { 
499                                         pa.load_from_file(this.path + "/.roobuilder.jcfg");
500                                 } catch (GLib.Error e) {
501                                         GLib.error("could not load json file %s", e.message);
502                                 }
503                                 var node = pa.get_root();
504
505                                 
506                                 if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
507                                         GLib.debug("SKIP %s/.roobuilder.jcfg  - invalid format?",this.path);
508                                         return;
509                                 }
510                                 
511                                 var obj = node.get_object ();
512                                  
513                                 this.loadJson(obj);
514                         } 
515                         // used to load paths..
516                         this.sub_paths = new Gee.ArrayList<JsRender.JsRender>();
517                         this.files = new Gee.HashMap<string,JsRender.JsRender>();
518                         this.loadSubDirectories("", 0);
519                          
520                         this.initDatabase();
521                         this.is_scanned = true; // loaded.. dont need to do it again..
522                          GLib.debug("load is_scanned = true");
523                         
524                 }
525                 
526                 public abstract void loadJson(Json.Object obj); 
527                 public abstract void saveJson(Json.Object obj);
528                 
529                 /*
530                 
531                 public string firstPath()
532                 {
533                         var iter = this.paths.map_iterator();
534                         while (iter.next()) {
535                                 return iter.get_key();
536                         }
537                   
538                         return "";
539                 }
540
541                 public bool hasPath(string path)
542                 {
543                         var iter = this.paths.map_iterator();
544                         while (iter.next()) {
545                                 if (iter.get_key() == path) {
546                                 return true;
547                         }
548                         }
549                   
550                         return false;
551                 }
552
553                 
554                 // returns the first path
555                 public string getName()
556                 {
557                         var iter = this.paths.map_iterator();
558                         while (iter.next()) {
559                                 return GLib.Path.get_basename(iter.get_key());
560                         }
561                   
562                         return "";
563                 }
564                 */
565
566                 public Gee.ArrayList<JsRender.JsRender> sortedFiles()
567                 {
568                         var files = new Gee.ArrayList<JsRender.JsRender>();
569
570                         var fiter = this.files.map_iterator();
571                         while(fiter.next()) {
572                                 files.add(fiter.get_value());
573                         }
574                         files.sort((fa,fb) => {
575                                 return ((JsRender.JsRender)fa).name.collate(((JsRender.JsRender)fb).name);
576
577                         });
578                         return files;
579
580                 }
581                 
582          
583          
584                 public string listAllFilesToString()
585                 {
586                  
587                         var iter = this.sortedFiles().list_iterator();
588                         var ret = "ID\tName\tDirectory\n";
589                         while (iter.next()) {
590                                 ret += "%s\n".printf(
591                                                  
592                                                 iter.get().name
593                                                  
594                                                 );
595                          
596                                 
597                         }
598                         
599                         return ret;
600                 
601                 }
602                 
603          
604          
605          
606                 public JsRender.JsRender? getByName(string name)
607                 {
608                         foreach(var f in this.files.values) {
609                                 if (f.name == name) {
610                                         return f;
611                                 }
612                         };
613                         return null;
614                 }
615                 // this get's a file using the full path ( replaces vala->bjs if they exist);
616                 
617                 public JsRender.JsRender? getByPath(string path)
618                 {
619                  
620                         // keys are not paths...
621                         foreach(var f in this.files.values) {
622                                 GLib.debug("check %s = %s ? %s", path, f.path, f.targetName());
623                                 if (f.path == path || f.targetName() == path) {
624                                         return f;
625                                 }
626                         };
627                         return null;                    
628                 }
629                 
630                 public JsRender.JsRender? getById(string id)
631                 {
632                         foreach(var f in this.files.values) {
633                                 if (f.id == id) {
634                                         return f;
635                                 }
636                         };
637                         return null;
638                 }
639  
640                 // name should include extension.       
641                 /*
642                 public JsRender.JsRender? newFile (string xtype, string sub_dir, string name)
643                 {
644                         try {
645                                 var fp = this.path + (sub_dir.length > 0  ? "/" : "") + sub_dir;
646                                 if (this.files.has_key(fp + "/" +  name)) {
647                                         return null;
648                                 }
649                                  
650                                 
651                                 var ret =  JsRender.JsRender.factory(xtype, 
652                                                                                          this, 
653                                                                                          fp + "/" +  name
654                                                                                          );
655                                 this.files.set(fp + "/" +  name , ret);
656                                 return ret;
657                         } catch (JsRender.Error e) {
658                                 GLib.error("failed to create file %s", e.message);
659                         }
660                 }
661                 */
662          
663                 public JsRender.JsRender loadFileOnly (string path)
664                 {
665                         var xt = this.xtype;
666                         try {
667                                 return JsRender.JsRender.factory(xt, this, path);
668                         } catch (JsRender.Error e) {
669                                 GLib.error("failed to create file %s", e.message);
670                         } 
671                         
672                 } 
673                 
674                 /* 
675                 public JsRender.JsRender create(string filename)
676                 {
677                         var ret = this.loadFileOnly(filename);
678                         ret.save();
679                         this.addFile(ret);
680                         return ret;
681                         
682                 }
683                 */
684                 private void loadSubDirectories(string subdir, int dp) 
685                 {
686                         //dp = dp || 0;
687                         //print("Project.Base: Running scandir on " + dir +"\n");
688                         if (dp > 5) { // no more than 5 deep?
689                                 return;
690                         }
691                         if (subdir == "build") { // cmake!
692                                 return;
693                         }
694                         
695                         if (subdir == "autom4te.cache") { // automake?
696                                 return;
697                         }
698                         if (subdir == "debian") { // debian!?
699                                 return;
700                         }
701
702                         
703                         var dir = this.path + (subdir.length > 0 ? "/" : "") + subdir;
704                         
705                         
706                         GLib.debug("Project %s Scan Dir: %s", this.name, dir);
707                         var jsDir = new JsRender.Dir(this, dir);
708                         this.sub_paths.add(jsDir); // might be ''...
709                         
710                         
711                         // this should be done async -- but since we are getting the proto up ...
712                         var other_files = new Gee.ArrayList<string>();
713                         var bjs_files = new Gee.ArrayList<string>();
714                         var vala_files = new Gee.ArrayList<string>();
715                         var subs = new Gee.ArrayList<string>();
716                         
717                         
718                         var f = File.new_for_path(dir);
719                         try {
720                                 var file_enum = f.enumerate_children(GLib.FileAttribute.STANDARD_DISPLAY_NAME, GLib.FileQueryInfoFlags.NONE, null);
721                                 
722                                  
723                                 FileInfo next_file; 
724                                 while ((next_file = file_enum.next_file(null)) != null) {
725                                         var fn = next_file.get_display_name();
726                         
727                                          
728                                         //print("trying"  + dir + "/" + fn +"\n");
729                                         
730                                         if (fn[0] == '.') { // skip hidden
731                                                 continue;
732                                         }
733                                         
734                                         if (FileUtils.test(dir  + "/" + fn, GLib.FileTest.IS_DIR)) {
735                                                 subs.add(dir  + "/" + fn);
736                                                 continue;
737                                         }
738                                         if (Regex.match_simple("\\.(o|cache|gif|jpg|png|gif|out|stamp|~)$", fn)) { // object..
739                                                 continue;
740                                         }
741                                         if (Regex.match_simple("^(config1.builder|a.out|stamp-h1|depcomp|config.log|config.status)$", fn)) { // object..
742                                                 continue;
743                                         }
744                                         
745                                         
746                                         if (Regex.match_simple("\\.vala$", fn)) {
747                                                 vala_files.add(fn);
748                                                 other_files.add(fn);
749                                                 //print("no a bjs\n");
750                                                 continue;
751                                         }
752                                         if (!Regex.match_simple("\\.bjs$", fn)) {
753                                                 other_files.add(fn);
754                                                 //print("no a bjs\n");
755                                                 continue;
756                                         }
757                                         bjs_files.add(fn.substring(0, fn.length-4));
758                                         
759                                         var xt = this.xtype;
760                                         var el = JsRender.JsRender.factory(xt,this, dir + "/" + fn);
761                                         this.files.set( dir + "/" + fn, el);
762                                         jsDir.childfiles.append(el);
763                                         
764                                         // parent ?? 
765                                         
766                                          
767                                 }
768                         } catch (Error e) {
769                                 GLib.warning("Project::scanDirs failed : " + e.message + "\n");
770                         } catch (GLib.Error e) {
771                                 GLib.warning("Project::scanDirs failed : " + e.message + "\n");
772                         } 
773
774                         foreach(var fn in other_files) {
775                                 var dpos = fn.last_index_of(".");
776                                 var without_ext = fn.substring(0, dpos);
777                                 if (bjs_files.contains(without_ext)) {  // will remove vala and c.
778                                         continue;
779                                 }
780                                 // c with a vala - skip
781                                 if (Regex.match_simple("\\.c$", fn) && vala_files.contains(without_ext + ".vala")) {
782                                         continue;
783                                 }
784                                 // Makefile (only allow am files at present.
785                                 if (without_ext == "Makefile") {
786                                         if (!Regex.match_simple("\\.am$", fn)) {
787                                                 continue;
788                                         }
789                                 }
790                                 if (without_ext == "configure") {
791                                         if (!Regex.match_simple("\\.ac$", fn)) {
792                                                 continue;
793                                         }
794                                 }
795                                 
796                                 
797                                 
798                                 
799                                 
800                                 //GLib.debug("Could have added %s/%s", dir, fn);
801                                 try {
802                                          var el = JsRender.JsRender.factory("PlainFile",this, dir + "/" + fn);
803                                          this.files.set( dir + "/" + fn, el);
804                                         jsDir.childfiles.append(el);
805                                 } catch (JsRender.Error e) {
806                                         GLib.warning("Project::scanDirs failed : " + e.message + "\n");
807                                 }
808                         }
809                         
810                         foreach (var sd in subs) {
811                                  this.loadSubDirectories(sd.substring(this.path.length+1), dp+1);
812                         }
813                         
814                 
815                 }
816                 
817                 // calle dfrom new file dialog
818                 // add files to dires 
819                 // update 
820                         
821                  
822                 public void addFile(JsRender.JsRender pfile)
823                 { // add a single file, and trigger changed.
824                 
825                         if (pfile.xtype == "Gtk" || pfile.xtype == "Roo" ) {
826                                 this.files.set(pfile.path, pfile); // duplicate check
827                                 
828                                 if (pfile.xtype == "Gtk" && pfile.build_module != "") {
829                                 
830                                         var gfile = (JsRender.Gtk) pfile;
831                                         gfile.updateCompileGroup("", pfile.build_module);
832                                          
833                                 }
834                         }
835                         var sp = this.findDir(pfile.dir);
836                         sp.childfiles.append(pfile);    
837                                 
838
839                         this.on_changed();
840                 }
841                 
842                 
843                 
844                 public void deleteFile(JsRender.JsRender file) 
845                 {
846                         if (file.xtype =="Dir") {
847                                 return;
848                         }
849                         var sp = this.findDir(file.dir);
850                         for(var i =0;i < sp.childfiles.n_items; i++) {
851                                 var jf = (JsRender.JsRender) sp.childfiles.get_item(i);
852                                 if (jf.path == file.path) {
853                                         sp.childfiles.remove(i);
854                                         break;
855                                 }
856                         }
857                         if (this.files.has_key(file.path)) {
858                                 this.files.unset(file.path);
859                         }
860
861                         
862                         file.remove();
863                         // remove it from 
864                         
865                         
866                 }
867                         
868                 // but do not add it to our list.!!!
869                 public void makeProjectSubdir(string name)
870                 {
871                         var dir = File.new_for_path(this.path + "/" + name);
872                         if (FileUtils.test(this.path + "/" + name, FileTest.EXISTS)) {
873                                 return;
874                         }
875                         try {
876                                  
877                                 dir.make_directory();   
878                         } catch (GLib.Error e) {
879                                 GLib.error("Failed to make directory %s", this.path + "/" + name);
880                         } 
881                 }
882                 
883                 public void createDir(string subdir)   // add a single dir, and trigger changed.
884                 {
885                         if (subdir.strip() == "" || this.subpathsContains(subdir)) {
886                                 return;
887                         }
888                         var dir= File.new_for_path(this.path + "/" + subdir);
889
890                         if (!dir.query_exists()) {
891                         
892                                 try {
893                                          
894                                         dir.make_directory();   
895                                 } catch (GLib.Error e) {
896                                         GLib.error("Failed to make directory %s", this.path + "/" + name);
897                                 }
898
899                         }
900                         this.sub_paths.add(new JsRender.Dir(this,this.path + "/" + subdir));
901                         this.on_changed();  // not sure if it's needed - adding a dir doesnt really change much.
902                 }
903                 
904                 // this store is used in the icon view ?? do we need to store and update it?
905                 public void loadFilesIntoStore(GLib.ListStore ls) 
906                 {
907                         ls.remove_all();
908                         //GLib.debug("Load files (into grid) %s", this.name);                   
909                         foreach(var f in this.files.values) {
910                         //      GLib.debug("Add file %s", f.name);
911                                 if (f.xtype == "PlainFile") {
912                                         continue;
913                                 }
914                                 ls.append(f);
915                         }
916                         
917                 }
918                 public void loadDirsIntoStore(GLib.ListStore  ls) 
919                 {
920                         ls.remove_all();
921                         foreach(var f in this.sub_paths) {
922                                 //GLib.debug("Add %s", f.name);
923                                 ls.append(f);
924                         }
925                          ;
926                 }
927                 
928                 public bool subpathsContains(string subpath) 
929                 {
930                         foreach(var sp in this.sub_paths) {
931
932                                 if (sp.path == this.path + "/" + subpath) {
933                                         return true;
934                                 }
935                         }
936                         return false;
937                         
938                 }
939                 
940                 public void loadDirsToStringList( global::Gtk.StringList sl, string prefix) 
941                 {
942                          
943                         while (sl.get_n_items() > 0) {
944                                 sl.remove(0);
945                         }
946                         
947                         foreach(var sp in this.sub_paths) {
948                                  var add = sp.path == this.path ? "/" : sp.path.substring(this.path.length);
949                                 if (prefix.length > 0 && !add.has_prefix(prefix)) {
950                                         continue;
951                                 }
952                                 sl.append(add);
953                         }
954                 
955                 }
956                 
957                 public JsRender.Dir? findDir(string path) {
958                         
959                         foreach(var jdir in this.sub_paths) { 
960                                 if (path == jdir.path) {
961                                         return (JsRender.Dir)jdir;
962                                 }
963                         }
964                         return null;
965                 }
966                 
967                 public string[] pathsMatching(string name, bool full_path)
968                 {
969                         string[] ret = {};
970                          
971                         foreach(var jdir in this.sub_paths) { 
972                                 
973
974                                 
975                                 if (Path.get_basename (jdir.path) == name) {
976                                         GLib.debug("pathsMatching %s\n", jdir.path);
977                                         ret += full_path ? jdir.path : jdir.relpath;
978                                 }
979                                 
980                         }
981                         return ret;
982                         
983                 }
984                 public Gee.ArrayList<string> readArray(Json.Array ar) 
985                 {
986                         var ret = new Gee.ArrayList<string>();
987                         for(var i =0; i< ar.get_length(); i++) {
988                                 var add = ar.get_string_element(i);
989                                 if (ret.contains(add)) {
990                                         continue;
991                                 }
992                         
993                                 ret.add(add);
994                         }
995                         return ret;
996                 }
997                 
998                  
999                  public abstract void initDatabase();
1000                  public abstract void initialize(); // for new projects (make dirs?);
1001                   
1002         }
1003 }
1004