Fix #8003 - undo code
[roobuilder] / src / JsRender / JsRender.vala
index adf5d55..593d8ff 100644 (file)
@@ -61,13 +61,37 @@ namespace JsRender {
                        private set {}
                }
                
-               
+               public string file_ext {
+                       public owned get {
+                               if (!this.path.contains(".")) {
+                                       return "";
+                               }
+                               var bits = this.name.split(".");
+                               return bits[bits.length-1];
+                       }
+                       private set {}
+               }
                public string parent = "";  // JS parent.
                public string region = "";  // RooJS - insert region.
         
                public string title = "";  // a title.. ?? nickname.. ??? -
 
-               
+               private int _version = 1;   // should we increment this based on the node..?
+               public int version {
+                       get {
+                               if (this.tree != null) {
+                                       return this.tree.updated_count;
+                               }
+                               return ++this._version; // increased on every call? - bit of a kludge until we do real versioning
+                       }
+                       private set {
+                               
+                               this._version = value;
+                               this.updateUndo();
+                       }
+                       
+               }
+
 
                public string permname;
                public string language;
@@ -95,11 +119,41 @@ namespace JsRender {
                
                public Gee.HashMap<string,string> transStrings; // map of md5 -> string.
                public  Gee.HashMap<string,string> namedStrings;
+               
+               public Gee.HashMap<int,string> undo_json;
+               
+               //public        Gee.HashMap<string, GLib.ListStore> errorsByType;
+               private Gee.ArrayList<Lsp.Diagnostic> errors;
+               public int error_counter {
+                       get; private set; default = 0;
+               }
 
-               public signal void changed (Node? node, string source); 
+               //public signal void changed (Node? node, string source);  (not used?)
                
                 
                public signal void compile_notice(string type, string file, int line, string message);
+               
+               private  GLib.Icon? _icon = null;
+               
+               public GLib.Icon? icon { 
+                       private set {}
+                       get {
+                               if (this._icon !=  null) {
+                                       return this._icon;
+                               }
+                               
+                               if (this.path == "") {
+                                       return null;
+                               }
+                               if (!GLib.FileUtils.test(this.path, GLib.FileTest.EXISTS)) {
+                                       return null;
+                               }
+                               this._icon = File.new_for_path(this.path).query_info("standard::icon",GLib.FileQueryInfoFlags.NONE).get_icon();
+                               return this._icon;
+                       }
+               }
+               
+               
                /**
                 * UI componenets
                 * 
@@ -110,10 +164,11 @@ namespace JsRender {
                
                //abstract JsRender(Project.Project project, string path); 
                
-               public void aconstruct(Project.Project project, string path)
+               protected JsRender(Project.Project project, string path)
                {
                    
                        //this.cn = new GLib.List<JsRender>();
+                       GLib.debug("new jsrender %s", path);
                        this.path = path;
                        this.project = project;
                        this.hasParent = false;
@@ -145,6 +200,10 @@ namespace JsRender {
 
                        this.doubleStringProps = new Gee.ArrayList<string>();
                        this.childfiles = new GLib.ListStore(typeof(JsRender));
+                       //this.errorsByType  = new Gee.HashMap<string, GLib.ListStore>();
+                       this.errors = new Gee.ArrayList<Lsp.Diagnostic>((a,b) => { return a.equals(b); }); 
+                       this.undo_json = new Gee.HashMap<int,string>();
+
 
                }
                
@@ -311,11 +370,14 @@ namespace JsRender {
                                 GLib.debug("Width %d, Height %d", widget.get_width(), widget.get_height()); 
                                 p.snapshot(s, widget.get_width(), widget.get_height());
                                 var n = s.free_to_node();
+                                if (n == null) {
+                                       return;
+                               }
                                 var r = new  Gsk.CairoRenderer();
                                 r.realize(null);
                                 var t = r.render_texture(n,null);
                                 GLib.debug("write to %s", filename);
-                               t.save_to_png(filename);
+                                t.save_to_png(filename);
                                 r.unrealize();
                                         
                        
@@ -385,13 +447,48 @@ namespace JsRender {
                        print("Save failed");
                    }
                }
-                
-                
-
-
-                
-                
-                
+               
+               bool in_undo = false;
+               protected void updateUndo()
+               {
+                       if (this.in_undo) {
+                               return;
+                       }
+                       if (this.xtype == "PlainFile") {
+                               // handled by gtk sourceview buffer...
+                               return;
+                       }
+                       //GLib.debug("UNDO store %d", this.version);
+                       this.undo_json.set(this.version, this.tree.toJsonString());
+                       if (this.undo_json.has_key(this.version+1)) {
+                               var n = this.version +1;
+                               while (this.undo_json.has_key(n)) {
+                                       this.undo_json.unset(n++);
+                               }
+                       
+                       }
+                       
+               }
+               
+               public bool undoStep(int step = -1) // undo back/next
+               {
+                       if (!this.undo_json.has_key(this.version + step)) {
+                               //GLib.debug("UNDO step %d failed - no version available", this.version + step);
+                               return false;
+                       }
+                       var new_version = this.version + step;
+                       var pa = new Json.Parser();
+                       //GLib.debug("UNDO RESTORE : %d",  this.version + step);
+                       
+                       pa.load_from_data(this.undo_json.get(new_version));
+                       var node = pa.get_root();
+                       this.in_undo = true;
+                       this.loadTree(node.get_object(),2); 
+                       this.tree.updated_count = new_version;
+                       this.in_undo = false;
+                       return true;
+               }
                  
                public string jsonHasOrEmpty(Json.Object obj, string key) {
                        return obj.has_member(key) ? 
@@ -676,8 +773,106 @@ namespace JsRender {
                        }
 
                }
+               public string relTargetName()
+               {
+                       return this.targetName().substring(this.project.path.length +1);
+               
+               }
+               
+               public string to_url()
+               {
+                       return File.new_for_path (this.targetName()).get_uri ();
+               }
+               public Palete.LanguageClient? getLanguageServer()
+               {
+                       
+                       return this.project.getLanguageServer(this.language_id());
+               
+               }
+                
+               public void updateErrors(Gee.ArrayList<Lsp.Diagnostic> new_errors) 
+               {
+                       var oc = this.error_counter;
+                       var skip = new Gee.ArrayList<Lsp.Diagnostic>((a,b) => { return a.equals(b); });
+                       var rem = new Gee.ArrayList<Lsp.Diagnostic>((a,b) => { return a.equals(b); });
+                       foreach(var old in this.errors) {
+                               if (new_errors.contains(old)) {
+                                       skip.add(old);
+                                       continue;
+                               }
+                               rem.add(old);
+                                
+                       }
+                       foreach(var old in  rem) {
+                               this.removeError(old);
+                       }
+                       foreach(var err in new_errors) {
+                               if (skip.contains(err)) {
+                                       continue;
+                               }
+                               this.addError(err);
+                       }
+                       if (oc != this.error_counter) {
+                               BuilderApplication.updateCompileResults();
+                       }
+                       
+               }
+               
+               
+               
+               public Gee.ArrayList<Lsp.Diagnostic> getErrors()
+               {
+                       return this.errors;
+               }
                
+               private void addError(Lsp.Diagnostic diag)
+               {
+                       
+                       GLib.debug("ADD Error %s", diag.to_string());
+                       this.errors.add(diag);
+                       this.project.addError(this, diag);
+                       
+                       this.error_counter++;
+                        
+               }
+                
+               public void removeError(Lsp.Diagnostic diag) 
+               {
+                       GLib.debug("REMOVE Error %s", diag.to_string());
+                       this.errors.remove(diag);
+                       this.project.removeError(this, diag);
+                       this.error_counter++;
+               }
+               public int getErrorsTotal(string category) 
+               {
+                       var  ret = 0;
+                       foreach(var diag in this.errors) {
+                               if (diag.category == category) {
+                                       ret++;
+                               }
+                       }
+                       return ret;
+                       
+               
+               } 
                
+               public void loadTree(Json.Object obj, int bjs_version = 2)
+               {
+                       if (this.xtype == "PlainFile" ){
+                               return;
+                       }
+                       Node.uid_count = 0;
+                       this.tree = new Node();
+                       this.tree.loadFromJson(obj,bjs_version);
+                       this.tree.version_changed.connect(() => {
+                               this.updateUndo();
+                       });
+               
+               }
+               
+               
+               
+               public abstract string language_id();
                public abstract void save();
                public abstract void saveHTML(string html);
                public abstract string toSource() ;
@@ -689,7 +884,10 @@ namespace JsRender {
                public abstract string toGlade();
                public abstract string targetName();
                public abstract void loadItems() throws GLib.Error;
+
        } 
+       
+        
 
 }