adf5d55f6a34c969ad203c1f5ee97798cb4efe08
[roobuilder] / src / JsRender / JsRender.vala
1 //<Script type="text/javascript">
2
3 namespace JsRender {
4
5
6         public errordomain Error {
7                 INVALID_FORMAT,
8                 RENAME_FILE_EXISTS
9         }
10                 
11         public abstract class JsRender  : Object {
12                 /**
13                  * @cfg {Array} doubleStringProps list of properties that can be double quoted.
14                  */
15                 public Gee.ArrayList<string> doubleStringProps;
16                 
17                 public string id  = "";
18                 public string name { get; set; default = ""; }   // is the JS name of the file.
19                 public string fullname = "";
20                 public string path = "";  // is the full path to the file.
21                 
22                 public  string relpath {
23                         owned get { 
24                                 return  this.project.path  == this.path ? "" : this.path.substring(this.project.path.length+1);
25                         } 
26                         private set {}
27                 }
28                 public  string reldir {
29                         owned get { 
30                                 return  this.project.path == this.dir ? "" : this. dir.substring(this.project.path.length+1);
31                         } 
32                         private set {}
33                 }
34                 
35                 public  string  dir {
36                         owned get { 
37                                 return GLib.Path.get_dirname(this.path);
38                                  
39                         } 
40                         private set {}
41                 }
42                 
43                 public string file_namespace {
44                         public owned get {
45                                 if (!this.name.contains(".")) {
46                                         return "";
47                                 }
48                                 var bits = this.name.split(".");
49                                 return bits[0];
50                         }
51                         private set {}
52                 }
53                 public string file_without_namespace {
54                         public  owned get {
55                                 if (!this.name.contains(".")) {
56                                         return this.name;
57                                 }
58                                 var bits = this.name.split(".");
59                                 return this.name.substring(bits[0].length +1);
60                         }
61                         private set {}
62                 }
63                 
64                 
65                 public string parent = "";  // JS parent.
66                 public string region = "";  // RooJS - insert region.
67         
68                 public string title = "";  // a title.. ?? nickname.. ??? -
69
70                 
71
72                 public string permname;
73                 public string language;
74                 public string content_type;
75                 public string modOrder;
76                 public string xtype;
77                 public uint64 webkit_page_id; // set by webkit view - used to extract extension/etc..
78                 public bool gen_extended  = false; // nodetovala??
79
80                 public Project.Project project;
81
82                 // GTK Specifc
83  
84                 public string build_module; // module to build if we compile (or are running tests...)      
85
86                 //Project : false, // link to container project!
87                 
88                 public Node tree; // the tree of nodes.
89                 
90                 //public GLib.List<JsRender> cn; // child files.. (used by project ... should move code here..)
91
92                 public bool hasParent; 
93                 
94                 public bool loaded;
95                 
96                 public Gee.HashMap<string,string> transStrings; // map of md5 -> string.
97                 public  Gee.HashMap<string,string> namedStrings;
98
99                 public signal void changed (Node? node, string source); 
100                 
101                  
102                 public signal void compile_notice(string type, string file, int line, string message);
103                 /**
104                  * UI componenets
105                  * 
106                  */
107                 //public Xcls_Editor editor;
108                 public GLib.ListStore childfiles; // used by directories..
109                 
110                 
111                 //abstract JsRender(Project.Project project, string path); 
112                 
113                 public void aconstruct(Project.Project project, string path)
114                 {
115                     
116                         //this.cn = new GLib.List<JsRender>();
117                         this.path = path;
118                         this.project = project;
119                         this.hasParent = false;
120                         this.parent = "";
121                         this.tree = null; 
122                         this.title = "";
123                         this.region = "";
124                         this.permname = "";
125                         this.modOrder = "";
126                         this.language = "";
127                         this.content_type = "";
128                         this.build_module = "";
129                         //this.loaded = false;
130                         //print("JsRender.cto() - reset transStrings\n");
131                         this.transStrings = new Gee.HashMap<string,string>();
132                         this.namedStrings = new Gee.HashMap<string,string>();
133                         // should use basename reallly...
134                         
135                         var ar = this.path.split("/");
136                         // name is in theory filename without .bjs (or .js eventually...)
137                         try {
138                                 Regex regex = new Regex ("\\.(bjs)$");
139
140                                 this.name = ar.length > 0 ? regex.replace(ar[ar.length-1],ar[ar.length-1].length, 0 , "") : "";
141                         } catch (GLib.Error e) {
142                                 this.name = "???";
143                         }
144                         this.fullname = (this.parent.length > 0 ? (this.parent + ".") : "" ) + this.name;
145
146                         this.doubleStringProps = new Gee.ArrayList<string>();
147                         this.childfiles = new GLib.ListStore(typeof(JsRender));
148
149                 }
150                 
151                 public void renameTo(string name) throws  Error
152                 {
153                         if (this.xtype == "PlainFile") {
154                                 return;
155                         }
156                         var bjs = GLib.Path.get_dirname(this.path) +"/" +  name + ".bjs";
157                         if (FileUtils.test(bjs, FileTest.EXISTS)) {
158                                 throw new Error.RENAME_FILE_EXISTS("File exists %s\n",name);
159                         }
160                         GLib.FileUtils.remove(this.path);
161                         this.removeFiles();
162                         // remove other files?
163                         
164                         this.name = name;
165                         this.path = bjs;
166                         
167                 }
168                 
169
170                 
171                 // not sure why xt is needed... -> project contains xtype..
172                 
173                 public static JsRender factory(string xt, Project.Project project, string path) throws Error
174                 {
175          
176                         switch (xt) {
177                                 case "Gtk":
178                                         return new Gtk(project, path);
179                                         
180                                 case "Roo":
181                                         return new Roo((Project.Roo) project, path);
182 //                      case "Flutter":
183 //                                      return new Flutter(project, path);
184                                 case "PlainFile":
185                                         return new PlainFile(project, path);
186                         }
187                         throw new Error.INVALID_FORMAT("JsRender Factory called with xtype=%s", xt);
188                         //return null;    
189                 }
190                 
191         
192         
193                 public string nickType()
194                 {
195                         var ar = this.name.split(".");
196                         string[] ret = {};
197                         for (var i =0; i < ar.length -1; i++) {
198                                 ret += ar[i];
199                         }
200                         return string.joinv(".", ret);
201                         
202                 }
203                 public string nickName()
204                 {
205                         var ar = this.name.split(".");
206                         return ar[ar.length-1];
207                         
208                 }
209                 
210                 public string nickNameSplit()
211                 {
212                         var n = this.nickName();
213                         var ret = "";
214                         var len = 0;
215                         for (var i = 0; i < n.length; i++) {
216                                 if (i!=0 && n.get(i).isupper() && len > 10) {
217                                         ret +="\n";
218                                         len= 0;
219                                 }
220                                 ret += n.get(i).to_string();
221                                 len++;
222                         }
223                         
224
225                         
226                         return ret;
227                 
228                 }
229                 
230                 Gdk.Pixbuf screenshot = null;
231                 Gdk.Pixbuf screenshot92 = null;
232                 Gdk.Pixbuf screenshot368 = null;
233                 
234                 public Gdk.Pixbuf? getIcon(int size = 0) {
235                     var fname = this.getIconFileName( );                
236                     if (!FileUtils.test(fname, FileTest.EXISTS)) {
237                 GLib.debug("PIXBUF %s:  %s does not exist?", this.name, fname);
238                                 return null;
239                         }
240                         
241                         switch (size) {
242                                 case 0:
243                                         if (this.screenshot == null) {
244                                                 try { 
245                                                         this.screenshot = new Gdk.Pixbuf.from_file(fname);
246                                                 } catch (GLib.Error e) {}
247                                         }
248                                         return this.screenshot;
249                                 
250                                 case 92:
251                                         
252                                         if (this.screenshot == null) {
253                                                 this.getIcon(0);
254                                                 if (this.screenshot == null) {
255                                                         return null;
256                                                 }
257                                         }
258                                         
259                                         this.screenshot92 = this.screenshot.scale_simple(92, (int) (this.screenshot.height * 92.0 /this.screenshot.width * 1.0 )
260                                                 , Gdk.InterpType.NEAREST) ;
261                                     return this.screenshot92;
262                             
263                             case 368:
264                                         if (this.screenshot == null) {
265                                                 this.getIcon(0);
266                                                 if (this.screenshot == null) {
267                                                         return null;
268                                                 }
269                                         }
270                                         
271                                         this.screenshot368 = this.screenshot.scale_simple(368, (int) (this.screenshot.height * 368.0 /this.screenshot.width * 1.0 )
272                                     , Gdk.InterpType.NEAREST) ;
273                                     return this.screenshot368;
274                     }
275                     return null;
276                 }
277                 
278                 public void writeIcon(Gdk.Pixbuf pixbuf) {
279                         
280                         this.screenshot92 = null;
281                         this.screenshot368 = null;
282                         this.screenshot = null;
283                         try {
284                                 GLib.debug("Wirte %s", this.getIconFileName( ));
285                                 pixbuf.save(this.getIconFileName( ),"png");
286                                 this.screenshot = pixbuf;
287                         
288                         } catch (GLib.Error e) {
289                                 GLib.debug("failed to write pixbuf?");
290                         
291                         }
292                                 
293                          
294                         
295                 
296                 }
297                 public void widgetToIcon(global::Gtk.Widget widget) {
298                         
299                         this.screenshot92 = null;
300                         this.screenshot368 = null;
301                         this.screenshot = null;
302                         
303                         try {
304                         
305
306                         var filename = this.getIconFileName();
307                                 
308
309                                  var p = new global::Gtk.WidgetPaintable(widget);
310                                  var s = new global::Gtk.Snapshot();
311                                  GLib.debug("Width %d, Height %d", widget.get_width(), widget.get_height()); 
312                                  p.snapshot(s, widget.get_width(), widget.get_height());
313                                  var n = s.free_to_node();
314                                  var r = new  Gsk.CairoRenderer();
315                                  r.realize(null);
316                                  var t = r.render_texture(n,null);
317                                  GLib.debug("write to %s", filename);
318                                 t.save_to_png(filename);
319                                  r.unrealize();
320                                          
321                         
322                         } catch (GLib.Error e) {
323                                 GLib.debug("failed to write pixbuf?");
324                         
325                         }
326                                 
327                          
328                         
329                 
330                 }
331
332                 
333                 public string getIconFileName( )
334                 {
335                          
336                         var m5 = GLib.Checksum.compute_for_string(GLib.ChecksumType.MD5,this.path); 
337
338                         var dir = GLib.Environment.get_home_dir() + "/.Builder/icons";
339                         try {
340                                 if (!FileUtils.test(dir, FileTest.IS_DIR)) {
341                                          File.new_for_path(dir).make_directory();
342                                 }
343                         } catch (GLib.Error e) {
344                                 // eakk.. what to do here...
345                         }
346                         var fname = dir + "/" + m5 + ".png";
347                         
348                          
349                         return fname;
350                           
351                 }
352                 
353                 public string toJsonString()
354                 {
355                         if (this.xtype == "PlainFile") {
356                                 return "";
357                         }
358                         var node = new Json.Node(Json.NodeType.OBJECT);
359                         node.set_object(this.toJsonObject());                   
360                         var generator = new JsonGen(node);
361                     generator.indent = 1;
362                     generator.pretty = true;
363                     
364                         
365                         return generator.to_data();
366                 }
367                 
368                 public void saveBJS()
369                 {
370                    // if (!this.loaded) {
371                         ///     GLib.debug("saveBJS - skip - not loaded?");
372                 //          return;
373                     //}
374                     if (this.xtype == "PlainFile") {
375                             return;
376                     }
377                    
378                      
379                     
380                     GLib.debug("WRITE :%s\n " , this.path);// + "\n" + JSON.stringify(write));
381                     try {
382                                 this.writeFile(this.path, this.toJsonString());
383                          
384                     } catch(GLib.Error e) {
385                         print("Save failed");
386                     }
387                 }
388                  
389                  
390
391
392                  
393                  
394                  
395                   
396                 public string jsonHasOrEmpty(Json.Object obj, string key) {
397                         return obj.has_member(key) ? 
398                                                 obj.get_string_member(key) : "";
399                 }
400
401                 
402                 public Json.Object toJsonObject ()
403                 {
404                     
405                     
406                         var ret = new Json.Object();
407                         if (this.xtype == "PlainFile") {
408                                 return ret;
409                         }
410                         
411                         //ret.set_string_member("id", this.id); // not relivant..
412                         ret.set_string_member("name", this.name);
413                         
414                         if (this.project.xtype == "Roo") {
415                                 ret.set_string_member("parent", this.parent == null ? "" : this.parent);
416                                 ret.set_string_member("title", this.title == null ? "" : this.title);
417                                 //ret.set_string_member("path", this.path);
418                                 //ret.set_string_member("items", this.items);
419                                 ret.set_string_member("permname", this.permname  == null ? "" : this.permname);
420                                 ret.set_string_member("modOrder", this.modOrder  == null ? "" : this.modOrder);
421                         }
422                         if (this.project.xtype == "Gtk") {
423  
424                                 ret.set_string_member("build_module", this.build_module  );
425                         }
426                         ret.set_boolean_member("gen_extended", this.gen_extended);
427                         
428                         if (this.transStrings.size > 0) {
429                                 var tr =  new Json.Object();
430                                 var iter = this.transStrings.map_iterator();
431                                 while (iter.next()) {
432                                         tr.set_string_member(iter.get_value(), iter.get_key());
433                                 }
434                                 ret.set_object_member("strings", tr);
435             }
436
437             
438             
439                         if (this.namedStrings.size > 0) {
440                                 var tr =  new Json.Object();
441                                 var iter = this.namedStrings.map_iterator();
442                                 while (iter.next()) {
443                                         tr.set_string_member(iter.get_key(), iter.get_value());
444                                 }
445                                 ret.set_object_member("named_strings", tr);
446             }
447                         
448                         var ar = new Json.Array();
449                         // empty files do not have a tree.
450                         if (this.tree != null) {
451                                 ar.add_object_element(this.tree.toJsonObject());
452                         }
453                         ret.set_array_member("items", ar);
454                 
455                     return ret;
456                 }
457                 
458                 
459
460                 public string getTitle ()
461                 {
462                     if (this.title == null) { // not sure why this happens..
463                         return "";
464                 }
465                     if (this.title.length > 0) {
466                         return this.title;
467                     }
468                     var a = this.path.split("/");
469                     return a[a.length-1];
470                 }
471                 public string getTitleTip()
472                 {
473                     if (this.title.length > 0) {
474                         return "<b>" + this.title + "</b> " + this.path;
475                     }
476                     return this.path;
477                 }
478                 /*
479                     sortCn: function()
480                     {
481                         this.cn.sort(function(a,b) {
482                             return a.path > b.path;// ? 1 : -1;
483                         });
484                     },
485                 */
486                     // should be in palete provider really..
487
488
489                 public Palete.Palete palete()
490                 {
491                         // error on plainfile?
492                         return this.project.palete;
493
494                 }
495                 
496                 public string guessName(Node ar) // turns the object into full name.
497                 {
498                      // eg. xns: Roo, xtype: XXX -> Roo.xxx
499                     if (!ar.hasXnsType()) {
500                        return "";
501                     }
502                     
503                     return ar.get("xns") + "." + ar.get("xtype");
504                                       
505                                         
506                 }
507                 /**
508                  *  non-atomic write (replacement for put contents, as it creates temporary files.
509                  */
510                 public void writeFile(string path, string contents) throws GLib.IOError, GLib.Error
511                 {
512
513                                  
514                         var f = GLib.File.new_for_path(path);
515                         var data_out = new GLib.DataOutputStream(
516                                           f.replace(null, false, GLib.FileCreateFlags.NONE, null)
517                        );
518                         data_out.put_string(contents, null);
519                         data_out.close(null);
520                 }
521                  
522                 
523                 
524                 public  Node? lineToNode(int line)
525                 {
526                         if (this.tree == null) {
527                                 return null;
528                         }
529                         return this.tree.lineToNode(line);
530                         
531                         
532                 }
533                 
534                 public GLib.ListStore toListStore()
535                 {
536                         var ret = new GLib.ListStore(typeof(Node));
537                         ret.append(this.tree);
538                         return ret;
539                 }
540                  
541                 
542                 // used to handle list of files in project editor (really Gtk only)
543                 public bool compile_group_selected {
544                         get {
545                                 var gproj = (Project.Gtk) this.project;
546                                 
547                                 if (gproj.active_cg == null) {
548                                         return false;
549                                 }
550                                 if (this.xtype == "Dir") {
551                                         // show ticked if all ticked..
552                                         var ticked = true;
553                                         for(var i = 0; i < this.childfiles.n_items; i++ ) {
554                                                 var f = (JsRender) this.childfiles.get_item(i);
555                                                 if (!f.compile_group_selected) {
556                                                         ticked = false;
557                                                         break;
558                                                 }
559                                         }
560                                         return ticked;
561                                 
562                                 
563                                 }
564                                 if (gproj.active_cg.sources == null) {
565                                         GLib.debug("compile_group_selected - sources is null? ");
566                                         return false;
567                                 }
568
569                                 return gproj.active_cg.sources.contains(this.relpath);
570                                 
571                         }
572                         set {
573                                 
574                                 var gproj = (Project.Gtk) this.project;
575                                 
576                                 if (gproj.active_cg == null) {
577                                         return;
578                                 }
579                                 if (gproj.active_cg.loading_ui) {
580                                         return;
581                                 }
582                                 
583                                 if (this.xtype == "Dir") {
584                                         for(var i = 0; i < this.childfiles.n_items; i++ ) {
585                                                 var f = (JsRender) this.childfiles.get_item(i);
586                                                 f.compile_group_selected = value;
587  
588                                         }
589                                         return;
590                                  
591                                 }
592                                 
593                                 
594                                 
595                                 if (value == false) {
596                                         GLib.debug("REMOVE %s", this.relpath);
597                                         
598                                         gproj.active_cg.sources.remove(this.relpath);
599                                         return;
600                                 }
601                                 if (!gproj.active_cg.sources.contains(this.relpath)) { 
602                                         GLib.debug("ADD %s", this.relpath);
603                                         gproj.active_cg.sources.add(this.relpath);
604                                 }
605                         
606                         }
607                 }
608                 /*
609                 public bool compile_group_hidden {
610                         get {
611                                 var gproj = (Project.Gtk) this.project;
612                                 
613                                 
614                                 return gproj.hidden.contains(this.relpath);
615                                 
616                         }
617                         set {
618                                 
619                                 var gproj = (Project.Gtk) this.project;
620                                 
621                                 if (gproj.active_cg == null) {
622                                         return;
623                                 }
624                                 if (gproj.active_cg.loading_ui) {
625                                         return;
626                                 } 
627                                 if (value == false) {
628                                         GLib.debug("REMOVE %s", this.relpath);
629                                         
630                                         gproj.hidden.remove(this.relpath);
631                                         return;
632                                 }
633                                 if (!gproj.hidden.contains(this.relpath)) { 
634                                         gproj.hidden.add(this.relpath);
635                                         // hiding a project will auto clear it.
636                                         for(var i = 0; i < this.childfiles.n_items; i++ ) {
637                                                 var f = (JsRender) this.childfiles.get_item(i);
638                                                 f.compile_group_selected = false;
639                                         }
640                                         return;
641                                         
642                                 }
643                         
644                         }
645                 }
646                 */
647                 public void remove()
648                 {
649                         if (this.xtype == "Dir") {
650                                 return;
651                         }
652                         // cleans up build (should really be in children..
653                         this.removeFile(this.path);
654                         if (this.path.has_suffix(".bjs") && this.project.xtype == "Roo") {
655                                 this.removeFile(this.path.substring(0, this.path.length-4) + ".js");
656                                 return;
657                         }
658                         if (this.path.has_suffix(".bjs") && this.project.xtype == "Gtk") {
659                                 this.removeFile(this.path.substring(0, this.path.length-4) + ".vala");
660                                 this.removeFile(this.path.substring(0, this.path.length-4) + ".c");
661                                 this.removeFile(this.path.substring(0, this.path.length-4) + ".o");                             
662                         }
663                         if (this.path.has_suffix(".vala") && this.project.xtype == "Gtk") {
664                                 this.removeFile(this.path.substring(0, this.path.length-5) + ".c");
665                                 this.removeFile(this.path.substring(0, this.path.length-5) + ".o");                             
666                         }       
667                 
668                 
669                 }
670                 
671                 private void removeFile(string path)
672                 {
673
674                         if (GLib.FileUtils.test(path, GLib.FileTest.EXISTS)) {
675                                 GLib.FileUtils.unlink(path);
676                         }
677
678                 }
679                 
680                 
681                 public abstract void save();
682                 public abstract void saveHTML(string html);
683                 public abstract string toSource() ;
684                 public abstract string toSourceCode() ; // used by commandline tester..
685                 public abstract void setSource(string str);
686                 public abstract string toSourcePreview() ;
687                 public abstract void removeFiles() ;
688                 public abstract void  findTransStrings(Node? node );
689                 public abstract string toGlade();
690                 public abstract string targetName();
691                 public abstract void loadItems() throws GLib.Error;
692         } 
693
694 }
695  
696