Merge branch 'master' of http://git.roojs.com/roobuilder
[roobuilder] / src / Project / Gtk.vala
1 //<Script type="text/javascript">
2 /**
3  * Gtk projects - normally vala based now..
4  * 
5  * should have a few extra features..
6  * 
7  * like:
8  *   compile flags etc..
9  *   different versions (eg. different files can compile different versions - eg. for testing.
10  *   
11  * If we model this like adjuta - then we would need a 'project' file that is actually in 
12  * the directory somewhere... - and is revision controlled etc..
13  * 
14  * builder.config ??
15  * 
16  * 
17  * 
18  * 
19  */
20  
21
22 namespace Project 
23 {
24  
25         
26
27         public class Gtk : Project
28         {
29                 /**
30                 * Gir cache - it's local as we might want clear it if we modify the packages...
31                 *
32                 */
33                 // public Gee.HashMap<string,Palete.GirObject> gir_cache = null; ?? 
34                 
35                 public bool gir_cache_loaded = false;  /// set this to false to force a relaod of vapi's?
36                 
37                 // these are loaded / created by the palete.. but are project specific.
38                 public Gee.HashMap<string,Gee.ArrayList<string>>? dropList = null;  
39             public Gee.HashMap<string,Gee.ArrayList<string>> child_list_cache;   // what child can on on what node
40                 public Gee.HashMap<string,Gee.ArrayList<string>> child_list_cache_props; // what child can go on what node (with properties included)
41                 
42             public string compile_flags = ""; // generic to all.        
43             public bool generate_meson = false; 
44              
45                 public Gee.ArrayList<string> packages; // list of vapi's that are used by this project. 
46                  
47                 //pblic Gee.ArrayList<string> hidden; // list of dirs to be hidden from display...
48                 
49                 public GtkValaSettings? active_cg = null;
50                 public Gee.HashMap<string,GtkValaSettings> compilegroups;
51                 public Meson meson;
52                 
53                 
54                 public Palete.Gtk gpalete {
55                         get {
56                                 return (Palete.Gtk) this.palete;
57                         }
58                         set {}
59                 }
60                  
61                 
62                 public Gtk(string path) {
63                   
64                   
65                         base(path);
66                         
67                         this.initChildCache();
68                    
69                         this.palete = new Palete.Gtk(this);
70                         
71                         this.gir_cache = new Gee.HashMap<string,Palete.GirObject>();
72                         this.xtype = "Gtk";
73                         //var gid = "project-gtk-%d".printf(gtk_id++);
74                         //this.id = gid;
75                         this.packages = new Gee.ArrayList<string>();
76                         //this.hidden = new Gee.ArrayList<string>();
77                         this.compilegroups = new  Gee.HashMap<string,GtkValaSettings>();
78                         this.meson = new Meson(this);
79                 
80                 }
81                 
82                 public  void initChildCache()
83                 {
84                         this.child_list_cache = new Gee.HashMap<string,Gee.ArrayList<string>>();
85                         this.child_list_cache_props = new Gee.HashMap<string,Gee.ArrayList<string>>();
86                         this.dropList = null;
87                 }
88                 
89                 
90                 
91                 public override void loadJson(Json.Object obj)  
92                 {
93                         // load a builder.config JSON file.
94                         // 
95                         this.compilegroups = new  Gee.HashMap<string,GtkValaSettings>();
96                         
97                         if (obj.has_member("packages")) {
98                                 this.packages = this.readArray(obj.get_array_member("packages"));
99                         }
100                         if (obj.has_member("compiler_flags")) {
101                                 this.compile_flags = obj.get_string_member("compile_flags");
102                         }
103                         if (obj.has_member("version")) {
104                                 this.version = obj.get_string_member("version");
105                         }
106                         if (obj.has_member("licence")) {
107                                 this.licence = obj.get_string_member("licence");
108                         }
109                         if (obj.has_member("generate_meson")) {
110                                 this.generate_meson = obj.get_boolean_member("generate_meson");
111                         }
112                          if (!obj.has_member("compilegroups") || obj.get_member("compilegroups").get_node_type () != Json.NodeType.ARRAY) {
113                                 // make _default_ ?
114                                  return;
115                          }
116                         
117                         //this.hidden = this.readArray(obj.get_array_member("hidden"));
118                         var ar = obj.get_array_member("compilegroups");
119                         for(var i= 0;i<ar.get_length();i++) {
120                                 var el = ar.get_object_element(i);
121                                 var vs = new GtkValaSettings.from_json(this,el);
122                 if (vs == null) {
123                     print("problem loading json file");
124                     continue;
125                 }
126                                  
127                                 this.compilegroups.set(vs.name,vs);
128                         }
129                                                 
130                          
131                         //GLib.debug("%s\n",this.configToString ());
132                         
133                 }
134                 public override void saveJson(Json.Object obj)
135                 {
136                         var ar = new Json.Array();
137                         foreach(var cg in this.compilegroups.values) {
138                                  ar.add_object_element(cg.toJson());
139                         }
140                         obj.set_array_member("compilegroups", ar);
141                         
142                         obj.set_string_member("compile_flags", this.compile_flags);
143                         obj.set_string_member("version", this.version);
144                         obj.set_string_member("licence", this.licence);
145                         obj.set_boolean_member("generate_meson",this.generate_meson);
146                         var par = new Json.Array();
147                         foreach(var p in this.packages) {
148                                 par.add_string_element(p);
149                         }
150                         obj.set_array_member("packages", par);
151                         //var hi = new Json.Array();
152                         //foreach(var p in this.hidden) {
153                         //      hi.add_string_element(p);
154                         //}
155                         //obj.set_array_member("hidden", hi);
156                         
157                         this.gir_cache_loaded = false; // force reload of the cache if we change the packages.
158                         this.gpalete.loaded = false;
159                         this.initChildCache();
160                         this.gir_cache = null;
161                 }
162                 
163                 public override void onSave()
164                 {
165                         if (this.generate_meson) {
166                                 this.meson.save();
167                         }
168                         var vl = this.language_servers.get("vala");
169                         if (vl != null) {
170                                 vl.initialize_server(); // hopefully better than exit?
171                         }
172                 }
173          
174                 /**
175                  *  perhaps we should select the default in the window somewhere...
176                  */ 
177                 public string firstBuildModule()
178                 {
179                         
180                         foreach(var cg in this.compilegroups.values) {
181                                 return cg.name;
182                                 
183                         }
184                         return "";
185                          
186                 }
187                 public string firstBuildModuleWith(JsRender.JsRender file)
188                 {
189                         foreach(var cg in this.compilegroups.values) {
190                                  if (cg.has_file(file)) {
191                                         return cg.name;
192                                  }
193                                  
194                                  
195                         }
196                         return this.firstBuildModule();
197                          
198                 }
199                 
200                 public void loadVapiIntoStore(GLib.ListStore ls) 
201                 {
202                         ls.remove_all();
203     
204                          
205                         var pal = (Palete.Gtk) this.palete;
206                         var pkgs = pal.packages(this);
207                         foreach (var p in pkgs) {
208                                 ls.append(new VapiSelection(this.packages, p));
209                         }
210                         
211                 }
212                 
213                 public void loadTargetsIntoStore(GLib.ListStore ls) 
214                 {
215                         ls.remove_all();
216                         foreach(var cg in this.compilegroups.values) {
217                                 ls.append(cg);
218                         }
219                 }
220                 
221                  
222                 
223                  
224                 
225                 public string[] vapidirs()
226                 {
227                         return this.pathsMatching("vapi", false);
228                 }
229                 
230                 
231                  
232                 public override Palete.LanguageClient getLanguageServer(string lang)
233                 {
234                         if (this.language_servers.has_key(lang)) {
235                                 return this.language_servers.get(lang);
236                         }
237                         
238                         GLib.debug("Get language Server %s", lang);
239                         switch( lang ) {
240                                 case "vala":
241                                 case "c": // not really... but we like it..
242                                         var ls = new Palete.LanguageClientVala(this);
243                                         ls.log.connect((act, msg) => {
244                                                 //GLib.debug("log %s: %s", act.to_string(), msg);
245                                                 BuilderApplication.showSpinnerLspLog(act,msg);
246                                         });
247                                         this.language_servers.set(lang, ls);
248                                         break;
249                                 default :
250                                          return this.language_servers.get("dummy");
251                                          
252                                 }
253                                 return this.language_servers.get(lang);
254                 
255                 }
256                  
257                  
258                  
259                  
260                  
261                  
262                  // ------------------  new project stufff
263                 public override void initialize()
264                 {
265                         this.generate_meson = true; // default to true on new projects.
266                         
267                         string[] dirs = {
268                                 "src",
269                                 "src/ui"
270                                 // ?? docs ?
271                                 //   
272                         };
273                         
274                         
275                         string[] vapis = {
276                                 "gtk4",
277                                 "gee-0.8",
278                                 "gio-2.0",
279                                  
280                                 "glib-2.0",
281                                 "gobject-2.0",
282                                  
283                                 // "json-glib-1.0",
284                                  
285                                 //"libadwaita-1",
286                                 //"libxml-2.0",
287                                 "posix"
288                                  
289  
290                         };
291                         for(var i = 0;  i < dirs.length; i++) {
292                                 this.makeProjectSubdir( dirs[i]);
293                         }
294                         for(var i = 0;  i < vapis.length; i++) {
295                                 this.packages.add(vapis[i]);
296                         
297                         }
298                         // create/// some dummy files?
299                         // application
300                         
301                         this.makeMain();
302                         this.makeApplication();
303                         this.makeWindow();
304                         this.makeGitIgnore();
305
306                         var cg =  new GtkValaSettings(this, this.name);
307                         this.compilegroups.set(this.name, cg);
308                         cg.sources.add("src/Main.vala");
309                         cg.sources.add("src/%sApplication.vala".printf(this.name));
310                         cg.sources.add("src/ui/ui.Window.bjs");
311                         // rescan... not needed as it get's selected after initialization.
312                         this.load();
313                         var fn = this.getByPath(this.path + "/src/ui/ui.Window.bjs");
314                         try {
315                                 fn.loadItems();
316                         } catch (GLib.Error e) { } // do nothing?
317                         
318                         fn.save();
319                         
320                         
321                         
322                 }
323                 
324                 
325                 void makeTemplatedFile(string name, string[] str, string replace) 
326                 {
327                         var o = "";
328                         for(var i=0;i< str.length;i++) {
329                                 o += str[i].replace("%s", replace) + "\n";
330                         }
331                         this.writeFile(name, o);
332                 }
333                 public void writeFile(string name, string o) 
334                 {
335                         var f = GLib.File.new_for_path(this.path + "/" + name);
336                         try {
337                                 var data_out = new GLib.DataOutputStream( f.replace(null, false, GLib.FileCreateFlags.NONE, null) );
338                                 data_out.put_string(o, null);
339                                 data_out.close(null);
340                         } catch (GLib.Error e) {
341                                 GLib.debug("Error writing file %s", e.message);
342                         }
343                         
344                 } 
345                 
346                 void makeMain()
347                 {
348                         string[] str = {
349                                 "int main (string[] args)",
350                                 "{",
351                                 "       var app = new  %sApplication(  args);",
352                                 "       Gtk.init ();",
353                                 "       GLib.Log.set_always_fatal(LogLevelFlags.LEVEL_ERROR ); ",
354                                 "       app.activate.connect(() => {",
355                                 "               var w = new ui.Window();",   // ?? main window as UI window?
356                                 "               w.el.application  = app;",
357                                 "               w.ref();",
358                                 "               w.show();",
359                                 "       });",
360                                 "       var ret = app.run(args);",
361                                 "       return ret; ",
362                                 "}"
363                         };
364                         this.makeTemplatedFile("src/Main.vala", str, this.name); // fixme name needs to be code friendly!
365                 }
366                 void makeApplication()
367                 {
368                         string[] str = {
369                         
370                         
371                                 "public class %sApplication : Gtk.Application",
372                                 "{",
373                                 "       public %sApplication (string[] args) ",
374                                 "       {",
375                                 "               Object(",
376                                 "                       application_id: \"org.roojs.%s\",",
377                                 "                       flags: ApplicationFlags.FLAGS_NONE",
378                                 "               );",
379                                 "       }",
380                                 "}"
381                         };
382                                 
383                         
384                         this.makeTemplatedFile("src/%sApplication.vala".printf(this.name), str, this.name); // fixme name needs to be code friendly!
385                 }
386
387                 
388                 void makeWindow()
389                 {
390                         this.writeFile("src/ui/ui.Window.bjs", """{
391  "build_module" : "",
392  "items" : [
393   {
394    "$ xns" : "Gtk",
395    "| void show" : "() { this.el.show(); }",
396    "items" : [
397     {
398      "$ xns" : "Gtk",
399      "* prop" : "child",
400      "Gtk.Orientation orientation" : "Gtk.Orientation.HORIZONTAL",
401      "int spacing" : 0,
402      "items" : [
403       {
404        "$ xns" : "Gtk",
405        "string label" : "Hello World",
406        "xtype" : "Label"
407       }
408      ],
409      "xtype" : "Box"
410     }
411    ],
412    "xtype" : "Window"
413   }
414  ],
415  "name" : "ui.Window",
416  "gen_extended" : false
417 }
418 """);
419         }
420         void makeGitIgnore()
421         {
422                         this.writeFile(".gitignore", """
423 build/
424 """);
425         }
426                         
427                 
428                  public override void   initDatabase()
429                 {
430                      // nOOP
431                 }
432         }
433          
434    
435 }