Revert "Branches.bjs"
authorAlan Knowles <alan@akbkhome.com>
Sun, 18 Sep 2011 16:00:16 +0000 (00:00 +0800)
committerAlan Knowles <alan@akbkhome.com>
Sun, 18 Sep 2011 16:00:16 +0000 (00:00 +0800)
This reverts commit b6a12f0edbda49cd40f669ec6226cdf7e2962bd8.

22 files changed:
Branches.bjs [new file with mode: 0644]
Branches.js [new file with mode: 0644]
Clones.bjs [new file with mode: 0644]
Clones.js [new file with mode: 0644]
Commit.bjs [new file with mode: 0644]
Commit.js [new file with mode: 0644]
Date.js [new file with mode: 0644]
GitMonitor.js [new file with mode: 0644]
Merger.bjs [new file with mode: 0644]
Merger.js [new file with mode: 0644]
Monitor.js [new file with mode: 0644]
RemoteEdit.bjs [new file with mode: 0644]
RemoteEdit.js [new file with mode: 0644]
Remotes.bjs [new file with mode: 0644]
Remotes.js [new file with mode: 0644]
Repo.js [new file with mode: 0644]
Spawn.js [new file with mode: 0644]
StatusIcon.js [new file with mode: 0644]
WindowLog.js [new file with mode: 0644]
XObject.js [new file with mode: 0644]
git_tool_notes.txt [new file with mode: 0644]
gitlive.js [new file with mode: 0644]

diff --git a/Branches.bjs b/Branches.bjs
new file mode 100644 (file)
index 0000000..1e8bd44
--- /dev/null
@@ -0,0 +1,152 @@
+{
+    "id": "file-gtk-6",
+    "name": "Branches",
+    "parent": "",
+    "title": false,
+    "path": "/home/alan/gitlive/gitlive/Branches.bjs",
+    "items": [
+        {
+            "listeners": {
+                "destroy_event": "function (self, event) {\n     this.el.hide();\n                return false;\n}",
+                "response": "function (self, id) {\n  // hide\n     //if (id < 1) {\n        this.el.hide();\n        return;\n    //}\n    if (typeof(this.get('bug').getValue()) != 'object') {\n        print(\"ERROR\");\n        return;\n    }\n \n    this.el.hide();\n        \n    //var val = this.get('bug').getValue();\n     //   Seed.print(val);\n}"
+            },
+            " modal": true,
+            "border_width": 3,
+            "default_height": 300,
+            "default_width": 500,
+            "title": "Branches",
+            "xtype": "Dialog",
+            "|deletable": true,
+            "|modal": true,
+            "|show": "function(c) {\n    \n    if (!this.el) {\n        this.init();\n    }\n    var _this = this;\n    this.get('/branchStore').load();\n    this.el.show_all();\n    \n    var run_ret = this.el.run();\n    if (run_ret < 1 ) {\n        return  \"DONE\";\n    }\n    print(\"RUN RETURN : \" + run_ret);\n    return \"DONE\";\n    \n}\n",
+            "|xns": "Gtk",
+            "items": [
+                {
+                    "xtype": "VBox",
+                    "|pack": " function(p,e) {\n        p.el.get_content_area().pack_start(e.el,true,true,0)\n    }\n",
+                    "|xns": "Gtk",
+                    "items": [
+                        {
+                            "pack": "pack_start,false,true",
+                            "xtype": "HBox",
+                            "|xns": "Gtk",
+                            "items": [
+                                {
+                                    "listeners": {
+                                        "clicked": "function (self) {\n\n     return;\n    var RemoteEdit=    imports.RemoteEdit.RemoteEdit\n     RemoteEdit.repo = Remotes.repo;\n    RemoteEdit.el.set_transient_for(Remotes.el);\n\n    var res =  RemoteEdit.show();\n    \n    if (res != false) {\n        Remotes.repo.remotes(res);\n    }\n    \n    this.get('/remotesStore').load();\n\n    \n}"
+                                    },
+                                    "label": "Pull",
+                                    "pack": "add",
+                                    "xtype": "Button",
+                                    "|xns": "Gtk"
+                                }
+                            ]
+                        },
+                        {
+                            "xtype": "ScrolledWindow",
+                            "|init": "function() {\n    XObject.prototype.init.call(this);\n      this.el.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)\n}\n",
+                            "|xns": "Gtk",
+                            "items": [
+                                {
+                                    "listeners": {
+                                        "cursor_changed": "function (self)\n{\n\n   return;\n  // SEE SELECTION.CHANGED\n    if (this.el.get_selection().count_selected_rows() < 1) {\n        //nothing? - clea it?\n        return;\n    }\n        var ret = {};         \n    var model = this.get('/changedFilesStore');\n\n     var s = this.el.get_selection();\n     var files = [];\n    s.selected_foreach(function(model,p,iter) {\n    \n       files.push( model.get_value(iter, 0).value.get_string());\n     \n    });\n    this.get('/patchview').showDiff(files); \n    //var value = ''+ ret.model.get_value(ret.iter, 1).value.get_string();\n     //print(\"OUT?\" + value);// id..\n    // load the list in the right grid..\n     \n    return true;\n\n}"
+                                    },
+                                    "id": "branchView",
+                                    "pack": "add",
+                                    "xtype": "TreeView",
+                                    "|init": "function() {\n    XObject.prototype.init.call(this);\n        var description = new Pango.FontDescription.c_new();\n   description.set_size(8000);\n     this.el.modify_font(description);\n\n     this.selection = this.el.get_selection();\n      this.selection.set_mode( Gtk.SelectionMode.MULTIPLE);\n    var _this = this;\n  this.selection.signal['changed'].connect(function() {\n     _this.listeners.cursor_changed.apply(\n          _this, [ _this, '']\n       );\n             });\n  }\n",
+                                    "|xns": "Gtk",
+                                    "items": [
+                                        {
+                                            "id": "branchStore",
+                                            "pack": "set_model",
+                                            "xtype": "ListStore",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.set_column_types ( 3, [\n       GObject.TYPE_STRING, // file  \n      GObject.TYPE_STRING, // added\n      GObject.TYPE_STRING, // removed\n  ] );\n}\n",
+                                            "|load": "function(tr)\n{\n    //this.insert(citer,iter,0);\n    this.el.clear();\n    \n    var tr = Branches.repo.getBranches();\n    \n    \n    for(var i =0 ; i < tr.length; i++) {\n        var ret = {  };\n       \n        this.el.append(ret);\n        \n        //print(JSON.stringify(ret,null,4));\n        var lastrev = tr[i].lastrev;\n        var remoterev = tr[i].remoterev;\n        \n        var lastrev = lastrev.length ? lastrev : remoterev;\n        \n        if (lastrev != remoterev) {\n            lastrev = \"Out of sync: remote=\" + remoterev + \", local=\" + lastrev;\n        }\n        \n \n          \n        this.el.set_value(ret.iter, 0, ''  +  tr[i].name );\n        this.el.set_value(ret.iter, 1, '' + tr[i].remote );\n        this.el.set_value(ret.iter, 2, '' + lastrev );\n \n        \n    }     \n}",
+                                            "|xns": "Gtk"
+                                        },
+                                        {
+                                            "min_width": 70,
+                                            "pack": "append_column",
+                                            "resizable": true,
+                                            "title": "Local",
+                                            "xtype": "TreeViewColumn",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.add_attribute(this.items[0].el , 'markup', 0 );\n\n}\n",
+                                            "|xns": "Gtk",
+                                            "items": [
+                                                {
+                                                    "pack": "pack_start",
+                                                    "xtype": "CellRendererText",
+                                                    "|xns": "Gtk"
+                                                }
+                                            ]
+                                        },
+                                        {
+                                            "min_width": 70,
+                                            "pack": "append_column",
+                                            "resizable": true,
+                                            "title": "Remote",
+                                            "xtype": "TreeViewColumn",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.add_attribute(this.items[0].el , 'markup', 1 );\n\n}\n",
+                                            "|xns": "Gtk",
+                                            "items": [
+                                                {
+                                                    "pack": "pack_start",
+                                                    "xtype": "CellRendererText",
+                                                    "|xns": "Gtk"
+                                                }
+                                            ]
+                                        },
+                                        {
+                                            "min_width": 200,
+                                            "pack": "append_column",
+                                            "title": "Status",
+                                            "xtype": "TreeViewColumn",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.add_attribute(this.items[0].el , 'markup', 2 );\n\n}\n",
+                                            "|xns": "Gtk",
+                                            "items": [
+                                                {
+                                                    "pack": "pack_start",
+                                                    "xtype": "CellRendererText",
+                                                    "|xns": "Gtk"
+                                                }
+                                            ]
+                                        }
+                                    ]
+                                },
+                                {
+                                    "|xns": "Gtk",
+                                    "xtype": "TreeView",
+                                    "pack": false,
+                                    "items": [
+                                        {
+                                            "|xns": "Gtk",
+                                            "xtype": "ListStore",
+                                            "pack": false
+                                        }
+                                    ]
+                                }
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "label": "Cancel",
+                    "pack": "add_action_widget,0",
+                    "xtype": "Button",
+                    "|xns": "Gtk",
+                    "listeners": {}
+                },
+                {
+                    "id": "ok_button",
+                    "label": "OK",
+                    "pack": "add_action_widget,1",
+                    "xtype": "Button",
+                    "|xns": "Gtk"
+                }
+            ]
+        }
+    ],
+    "permname": "",
+    "modOrder": "0"
+}
\ No newline at end of file
diff --git a/Branches.js b/Branches.js
new file mode 100644 (file)
index 0000000..5e617c7
--- /dev/null
@@ -0,0 +1,281 @@
+Gtk = imports.gi.Gtk;
+Gdk = imports.gi.Gdk;
+Pango = imports.gi.Pango;
+GLib = imports.gi.GLib;
+Gio = imports.gi.Gio;
+GObject = imports.gi.GObject;
+GtkSource = imports.gi.GtkSource;
+WebKit = imports.gi.WebKit;
+Vte = imports.gi.Vte;
+console = imports.console;
+XObject = imports.XObject.XObject;
+Branches=new XObject({
+    xtype: Gtk.Dialog,
+    listeners : {
+        destroy_event : function (self, event) {
+             this.el.hide();
+                        return false;
+        },
+        response : function (self, id) {
+          // hide
+             //if (id < 1) {
+                this.el.hide();
+                return;
+            //}
+            if (typeof(this.get('bug').getValue()) != 'object') {
+                print("ERROR");
+                return;
+            }
+         
+            this.el.hide();
+                
+            //var val = this.get('bug').getValue();
+             //   Seed.print(val);
+        }
+    },
+    ' modal' : true,
+    border_width : 3,
+    default_height : 300,
+    default_width : 500,
+    title : "Branches",
+    deletable : true,
+    modal : true,
+    show : function(c) {
+        
+        if (!this.el) {
+            this.init();
+        }
+        var _this = this;
+        this.get('/branchStore').load();
+        this.el.show_all();
+        
+        var run_ret = this.el.run();
+        if (run_ret < 1 ) {
+            return  "DONE";
+        }
+        print("RUN RETURN : " + run_ret);
+        return "DONE";
+        
+    },
+    items : [
+        {
+            xtype: Gtk.VBox,
+            pack : function(p,e) {
+                    p.el.get_content_area().pack_start(e.el,true,true,0)
+                },
+            items : [
+                {
+                    xtype: Gtk.HBox,
+                    pack : "pack_start,false,true",
+                    items : [
+                        {
+                            xtype: Gtk.Button,
+                            listeners : {
+                                clicked : function (self) {
+                                
+                                     return;
+                                    var RemoteEdit=    imports.RemoteEdit.RemoteEdit
+                                     RemoteEdit.repo = Remotes.repo;
+                                    RemoteEdit.el.set_transient_for(Remotes.el);
+                                
+                                    var res =  RemoteEdit.show();
+                                    
+                                    if (res != false) {
+                                        Remotes.repo.remotes(res);
+                                    }
+                                    
+                                    this.get('/remotesStore').load();
+                                
+                                    
+                                }
+                            },
+                            label : "Pull",
+                            pack : "add"
+                        }
+                    ]
+                },
+                {
+                    xtype: Gtk.ScrolledWindow,
+                    init : function() {
+                        XObject.prototype.init.call(this);
+                          this.el.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
+                    },
+                    items : [
+                        {
+                            xtype: Gtk.TreeView,
+                            listeners : {
+                                cursor_changed : function (self)
+                                {
+                                
+                                   return;
+                                  // SEE SELECTION.CHANGED
+                                    if (this.el.get_selection().count_selected_rows() < 1) {
+                                        //nothing? - clea it?
+                                        return;
+                                    }
+                                        var ret = {};         
+                                    var model = this.get('/changedFilesStore');
+                                
+                                     var s = this.el.get_selection();
+                                     var files = [];
+                                    s.selected_foreach(function(model,p,iter) {
+                                    
+                                       files.push( model.get_value(iter, 0).value.get_string());
+                                     
+                                    });
+                                    this.get('/patchview').showDiff(files); 
+                                    //var value = ''+ ret.model.get_value(ret.iter, 1).value.get_string();
+                                     //print("OUT?" + value);// id..
+                                    // load the list in the right grid..
+                                     
+                                    return true;
+                                
+                                }
+                            },
+                            id : "branchView",
+                            pack : "add",
+                            init : function() {
+                                XObject.prototype.init.call(this);
+                                    var description = new Pango.FontDescription.c_new();
+                               description.set_size(8000);
+                                 this.el.modify_font(description);
+                            
+                                 this.selection = this.el.get_selection();
+                                  this.selection.set_mode( Gtk.SelectionMode.MULTIPLE);
+                                var _this = this;
+                              this.selection.signal['changed'].connect(function() {
+                                 _this.listeners.cursor_changed.apply(
+                                      _this, [ _this, '']
+                                   );
+                                         });
+                              },
+                            items : [
+                                {
+                                    xtype: Gtk.ListStore,
+                                    id : "branchStore",
+                                    pack : "set_model",
+                                    init : function() {
+                                        XObject.prototype.init.call(this);
+                                        this.el.set_column_types ( 3, [
+                                           GObject.TYPE_STRING, // file  
+                                          GObject.TYPE_STRING, // added
+                                          GObject.TYPE_STRING, // removed
+                                      ] );
+                                    },
+                                    load : function(tr)
+                                    {
+                                        //this.insert(citer,iter,0);
+                                        this.el.clear();
+                                        
+                                        var tr = Branches.repo.getBranches();
+                                        
+                                        
+                                        for(var i =0 ; i < tr.length; i++) {
+                                            var ret = {  };
+                                           
+                                            this.el.append(ret);
+                                            
+                                            //print(JSON.stringify(ret,null,4));
+                                            var lastrev = tr[i].lastrev;
+                                            var remoterev = tr[i].remoterev;
+                                            
+                                            var lastrev = lastrev.length ? lastrev : remoterev;
+                                            
+                                            if (lastrev != remoterev) {
+                                                lastrev = "Out of sync: remote=" + remoterev + ", local=" + lastrev;
+                                            }
+                                            
+                                     
+                                              
+                                            this.el.set_value(ret.iter, 0, ''  +  tr[i].name );
+                                            this.el.set_value(ret.iter, 1, '' + tr[i].remote );
+                                            this.el.set_value(ret.iter, 2, '' + lastrev );
+                                     
+                                            
+                                        }     
+                                    }
+                                },
+                                {
+                                    xtype: Gtk.TreeViewColumn,
+                                    min_width : 70,
+                                    pack : "append_column",
+                                    resizable : true,
+                                    title : "Local",
+                                    init : function() {
+                                        XObject.prototype.init.call(this);
+                                        this.el.add_attribute(this.items[0].el , 'markup', 0 );
+                                    
+                                    },
+                                    items : [
+                                        {
+                                            xtype: Gtk.CellRendererText,
+                                            pack : "pack_start"
+                                        }
+                                    ]
+                                },
+                                {
+                                    xtype: Gtk.TreeViewColumn,
+                                    min_width : 70,
+                                    pack : "append_column",
+                                    resizable : true,
+                                    title : "Remote",
+                                    init : function() {
+                                        XObject.prototype.init.call(this);
+                                        this.el.add_attribute(this.items[0].el , 'markup', 1 );
+                                    
+                                    },
+                                    items : [
+                                        {
+                                            xtype: Gtk.CellRendererText,
+                                            pack : "pack_start"
+                                        }
+                                    ]
+                                },
+                                {
+                                    xtype: Gtk.TreeViewColumn,
+                                    min_width : 200,
+                                    pack : "append_column",
+                                    title : "Status",
+                                    init : function() {
+                                        XObject.prototype.init.call(this);
+                                        this.el.add_attribute(this.items[0].el , 'markup', 2 );
+                                    
+                                    },
+                                    items : [
+                                        {
+                                            xtype: Gtk.CellRendererText,
+                                            pack : "pack_start"
+                                        }
+                                    ]
+                                }
+                            ]
+                        },
+                        {
+                            xtype: Gtk.TreeView,
+                            pack : false,
+                            items : [
+                                {
+                                    xtype: Gtk.ListStore,
+                                    pack : false
+                                }
+                            ]
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            xtype: Gtk.Button,
+            label : "Cancel",
+            pack : "add_action_widget,0"
+        },
+        {
+            xtype: Gtk.Button,
+            id : "ok_button",
+            label : "OK",
+            pack : "add_action_widget,1"
+        }
+    ]
+});
+Branches.init();
+XObject.cache['/Branches'] = Branches;
diff --git a/Clones.bjs b/Clones.bjs
new file mode 100644 (file)
index 0000000..1f08553
--- /dev/null
@@ -0,0 +1,234 @@
+{
+    "id": "file-gtk-2",
+    "name": "Clones",
+    "parent": "",
+    "title": false,
+    "path": "/home/alan/gitlive/gitlive/Clones.bjs",
+    "items": [
+        {
+            "listeners": {
+                "destroy_event": "function (self, event) {\n      print(\"DESTROY?!\");\n     return true;\n}",
+                "response": "function (self, id) {\n  // hide\n     //if (id < 1) {\n        this.el.hide();\n        return;\n    //}\n    if (typeof(this.get('bug').getValue()) != 'object') {\n        print(\"ERROR\");\n        return;\n    }\n \n    this.el.hide();\n        \n    //var val = this.get('bug').getValue();\n     //   Seed.print(val);\n}"
+            },
+            "border_width": 3,
+            "default_height": 500,
+            "default_width": 600,
+            "title": "Manage Clones",
+            "xtype": "Dialog",
+            "|deletable": "true",
+            "|modal": "true",
+            "|show": "function(c) {\n    \n    if (!this.el) {\n        this.init();\n    }\n    var _this = this;\n    /*[ 'xtype'  ].forEach(function(k) {\n        _this.get(k).setValue(typeof(c[k]) == 'undefined' ? '' : c[k]);\n    });\n\t// shouild set path..\n    */\n    this.el.set_deletable(false);\n    this.el.show_all();\n    // load clones..\n        this.get('/reposStore').load();\n    \n    //this.get('/ok_button').el.set_sensitive(false);\n    \n    // block until we return.\n    var run_ret = this.el.run();\n    if (run_ret < 1 ) {\n        return  \"DONE\";\n    }\n    print(\"RUN RETURN : \" + run_ret);\n    return \"DONE\";\n    //print(JSON.stringify(this.get('bug').getValue()));\n   // return this.get('bug').getValue();\n    //this.success = c.success;\n}\n",
+            "|xns": "Gtk",
+            "items": [
+                {
+                    "id": "Clones",
+                    "xtype": "VBox",
+                    "|pack": " function(p,e) {\n        p.el.get_content_area().pack_start(e.el,true,true,0)\n    }\n",
+                    "|xns": "Gtk",
+                    "items": [
+                        {
+                            "pack": "pack_start,false,true",
+                            "xtype": "HBox",
+                            "|xns": "Gtk",
+                            "items": [
+                                {
+                                    "listeners": {
+                                        "clicked": "function (self) {\n\n    var rv = this.get('/reposView');\n    var rs = this.get('/reposStore');\n    if (rv.el.get_selection().count_selected_rows() != 1) {\n        //nothing?\n        // error condition.\n        return;\n    }\n    var Remotes =     imports.Remotes.Remotes;\n    \n \n    var ret = {};       \n    var s = rv.el.get_selection();\n    var path = '';\n    s.selected_foreach(function(model,p,iter) {\n                                                    \n       path = model.get_value(iter, 6).value.get_string();\n     \n    }); \n\n    var repo = false;\n    rs.repos.forEach(function(r) {\n        if (r.repopath == path) {\n            repo = r;\n        \n        }\n    \n    });\n    Remotes.repo = repo;\n    Remotes.el.set_transient_for(Clones.el);\n    Clones.el.set_title(\"Manage Clones - \" + repo.repopath);\n    Remotes.show();\n    Clones.el.set_title(\"Manage Clones\");\n\n     \n    \n    \n    \n\n       \n    \n    \n}"
+                                    },
+                                    "label": "Remotes / Clones",
+                                    "pack": "add",
+                                    "xtype": "Button",
+                                    "|xns": "Gtk"
+                                },
+                                {
+                                    "listeners": {
+                                        "clicked": "function (self) {\n\n    var rv = this.get('/reposView');\n    var rs = this.get('/reposStore');\n    if (rv.el.get_selection().count_selected_rows() != 1) {\n        //nothing?\n        // error condition.\n        return;\n    }\n    var Branches =     imports.Branches.Branches;\n    \n \n    var ret = {};       \n    var s = rv.el.get_selection();\n    var path = '';\n    s.selected_foreach(function(model,p,iter) {\n                                                    \n       path = model.get_value(iter, 6).value.get_string();\n     \n    }); \n\n    var repo = false;\n    rs.repos.forEach(function(r) {\n        if (r.repopath == path) {\n            repo = r;\n        \n        }\n    \n    });\n    Branches.repo = repo;\n    Branches.el.set_transient_for(Clones.el);\n    Clones.el.set_title(\"Manage Clones - \" + repo.repopath);\n    Branches.show();\n    Clones.el.set_title(\"Manage Clones\");\n\n     \n    \n    \n    \n\n       \n    \n    \n}"
+                                    },
+                                    "label": "Branches",
+                                    "pack": "add",
+                                    "xtype": "Button",
+                                    "|xns": "Gtk"
+                                },
+                                {
+                                    "listeners": {
+                                        "clicked": "function (self) {\n\n    var rv = this.get('/reposView');\n    var rs = this.get('/reposStore');\n    if (rv.el.get_selection().count_selected_rows() != 1) {\n        //nothing?\n        // error condition.\n        return;\n    }\n    var Merger =     imports.Merger.Merger;\n    \n \n    var ret = {};       \n    var s = rv.el.get_selection();\n    var path = '';\n    s.selected_foreach(function(model,p,iter) {\n                                                    \n       path = model.get_value(iter, 6).value.get_string();\n     \n    }); \n\n    var repo = false;\n    rs.repos.forEach(function(r) {\n        if (r.repopath == path) {\n            repo = r;\n        \n        }\n    \n    });\n    Merger.repo = repo;\n    Merger.el.set_transient_for(Clones.el);\n    Clones.el.set_title(\"Manage Clones - \" + repo.repopath);\n    Merger.show();\n    Clones.el.set_title(\"Manage Clones\");\n\n    \n    \n\n    \n\n    \n    \n    \n    \n\n       \n    \n    \n}"
+                                    },
+                                    "label": "Run Merger",
+                                    "pack": "add",
+                                    "xtype": "Button",
+                                    "|xns": "Gtk"
+                                },
+                                {
+                                    "listeners": {
+                                        "clicked": "function (self) {\n    \n    \n \n       \n    \n    \n}"
+                                    },
+                                    "label": "Switch Branch",
+                                    "pack": "add",
+                                    "xtype": "Button",
+                                    "|xns": "Gtk"
+                                },
+                                {
+                                    "listeners": {
+                                        "clicked": "function (self) {\n    \n    \n \n       \n    \n    \n}"
+                                    },
+                                    "label": "Pull",
+                                    "pack": "add",
+                                    "xtype": "Button",
+                                    "|xns": "Gtk"
+                                }
+                            ]
+                        },
+                        {
+                            "xtype": "ScrolledWindow",
+                            "|init": "function() {\n    XObject.prototype.init.call(this);\n      this.el.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)\n}\n",
+                            "|xns": "Gtk",
+                            "items": [
+                                {
+                                    "listeners": {
+                                        "cursor_changed": "function (self) {\n  // SEE SELECTION.CHANGED\n  \n  \n  return;\n  \n    if (this.el.get_selection().count_selected_rows() < 1) {\n        //nothing? - clea it?\n        return;\n    }\n        var ret = {};         \n    var model = this.get('/changedFilesStore');\n\n     var s = this.el.get_selection();\n     var files = [];\n    s.selected_foreach(function(model,p,iter) {\n    \n       files.push( model.get_value(iter, 0).value.get_string());\n     \n    });\n    this.get('/patchview').showDiff(files); \n    //var value = ''+ ret.model.get_value(ret.iter, 1).value.get_string();\n     //print(\"OUT?\" + value);// id..\n    // load the list in the right grid..\n     \n    return true;\n\n}"
+                                    },
+                                    "id": "reposView",
+                                    "pack": "add",
+                                    "xtype": "TreeView",
+                                    "|init": "function() {\n    XObject.prototype.init.call(this);\n        var description = new Pango.FontDescription.c_new();\n   description.set_size(10000);\n     this.el.modify_font(description);\n\n     this.selection = this.el.get_selection();\n      this.selection.set_mode( Gtk.SelectionMode.MULTIPLE);\n    var _this = this;\n    \n    \n  this.selection.signal['changed'].connect(function() {\n     _this.listeners.cursor_changed.apply(\n          _this, [ _this, '']\n       );\n             });\n  }\n",
+                                    "|xns": "Gtk",
+                                    "items": [
+                                        {
+                                            "id": "reposStore",
+                                            "pack": "set_model",
+                                            "xtype": "ListStore",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.set_column_types ( 8, [\n       GObject.TYPE_STRING, // repo  \n      GObject.TYPE_STRING, // current branch\n      GObject.TYPE_STRING, // all branch      \n      GObject.TYPE_STRING, // updated\n       GObject.TYPE_BOOLEAN, // auto-commit\n        GObject.TYPE_BOOLEAN, // auto-push\n           GObject.TYPE_STRING, // repopath\n           GObject.TYPE_STRING // color highighling \n  ] );\n}\n",
+                                            "|load": "function()\n{\n    //this.insert(citer,iter,0);\n    print(\"getting list\");\n    this.repos = imports.Scm.Repo.Repo.list();\n    var tr= this.repos;\n    this.el.clear();\n    \n    for(var i =0 ; i < tr.length; i++) {\n        var ret = {  };\n       \n        this.el.append(ret);\n        \n        //print(JSON.stringify(ret,null,4));\n         tr[i].getBranches();\n         var hi;\n         try {\n             //tr[i].debug=1;\n              hi = tr[i].history('/', 1, 'branch', tr[i].currentBranch.name );\n//             print(JSON.stringify(hi,null,4));\n         } catch(e) { print(e);}\n          \n        this.el.set_value(ret.iter, 0, '' +  tr[i].repopath.split('/').pop() );\n        this.el.set_value(ret.iter, 1, '' + tr[i].currentBranch.name   );\n        this.el.set_value(ret.iter, 2, '' + tr[i].branches.map(\n                        function(e) { return e.name; \n                    }).join(', ') \n         );\n        this.el.set_value(ret.iter, 3, '' +  (!hi  ? '??' : hi[0].changed_raw));        \n        this.el.set_value(ret.iter, 4, tr[i].autocommit() );                \n        this.el.set_value(ret.iter, 5, tr[i].autopush() );                        \n        this.el.set_value(ret.iter, 6,  tr[i].repopath );  \n        // highlight color.\n        var cb = tr[i].currentBranch;\n        //print(JSON.stringify(cb,null,4));\n        var col = cb.lastrev == cb.remoterev ? '#ffffff' : '#ff0000';\n        this.el.set_value(ret.iter, 7, col  );      \n        \n    }     \n}",
+                                            "|xns": "Gtk"
+                                        },
+                                        {
+                                            "min_width": 50,
+                                            "pack": "append_column",
+                                            "title": "Auto Commit",
+                                            "xtype": "TreeViewColumn",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.add_attribute(this.items[0].el , 'active', 4 );\n    this.items[0].el.set_activatable(true);\n\n}\n",
+                                            "|xns": "Gtk",
+                                            "items": [
+                                                {
+                                                    "listeners": {
+                                                        "toggled": "function (self, path) {\n    var ret ={} ;\n    var store = this.get('/reposStore');\n    store.el.get_iter_from_string(ret, path);\n                                                                 \n    var value =   store.el.get_value(ret.iter,4).value.get_boolean();\n                                                                 \n    //print(JSON.stringify(value));\n    store.el.set_value(ret.iter,4, !value);\n    \n}"
+                                                    },
+                                                    "pack": "pack_start",
+                                                    "xtype": "CellRendererToggle",
+                                                    "|mode": "Gtk.CellRendererMode.ACTIVATABLE",
+                                                    "|xns": "Gtk"
+                                                }
+                                            ]
+                                        },
+                                        {
+                                            "min_width": 50,
+                                            "pack": "append_column",
+                                            "title": "Auto Push",
+                                            "xtype": "TreeViewColumn",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.add_attribute(this.items[0].el , 'active', 5 );\n      this.items[0].el.set_activatable(true);\n}\n",
+                                            "|xns": "Gtk",
+                                            "items": [
+                                                {
+                                                    "listeners": {
+                                                        "toggled": "function (self, path) {\n    var ret ={} ;\n    var store = this.get('/reposStore');\n    store.el.get_iter_from_string(ret, path);\n                                                                 \n    var value =   store.el.get_value(ret.iter,5).value.get_boolean();\n                                                                 \n    //print(JSON.stringify(value));\n    store.el.set_value(ret.iter,5, !value);\n    \n}"
+                                                    },
+                                                    "pack": "pack_start",
+                                                    "xtype": "CellRendererToggle",
+                                                    "|mode": "Gtk.CellRendererMode.ACTIVATABLE",
+                                                    "|xns": "Gtk"
+                                                }
+                                            ]
+                                        },
+                                        {
+                                            "min_width": 200,
+                                            "pack": "append_column",
+                                            "resizable": true,
+                                            "title": "Repo",
+                                            "xtype": "TreeViewColumn",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.add_attribute(this.items[0].el , 'markup', 0 );\n\n}\n",
+                                            "|xns": "Gtk",
+                                            "items": [
+                                                {
+                                                    "pack": "pack_start",
+                                                    "xtype": "CellRendererText",
+                                                    "|xns": "Gtk"
+                                                }
+                                            ]
+                                        },
+                                        {
+                                            "min_width": 50,
+                                            "pack": "append_column",
+                                            "title": "Current Branch",
+                                            "xtype": "TreeViewColumn",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.add_attribute(this.items[0].el , 'markup', 1 );\n     this.el.add_attribute(this.items[0].el , 'cell-background', 7 );\n\n}\n",
+                                            "|xns": "Gtk",
+                                            "items": [
+                                                {
+                                                    "pack": "pack_start",
+                                                    "xtype": "CellRendererText",
+                                                    "|xns": "Gtk"
+                                                }
+                                            ]
+                                        },
+                                        {
+                                            "min_width": 50,
+                                            "pack": "append_column",
+                                            "title": "Last updated",
+                                            "xtype": "TreeViewColumn",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.add_attribute(this.items[0].el , 'markup', 3 );\n\n}\n",
+                                            "|xns": "Gtk",
+                                            "items": [
+                                                {
+                                                    "pack": "pack_start",
+                                                    "xtype": "CellRendererText",
+                                                    "|xns": "Gtk"
+                                                }
+                                            ]
+                                        },
+                                        {
+                                            "min_width": 50,
+                                            "pack": "append_column",
+                                            "resizable": false,
+                                            "title": "All Branches",
+                                            "xtype": "TreeViewColumn",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.add_attribute(this.items[0].el , 'markup', 2 );\n\n}\n",
+                                            "|xns": "Gtk",
+                                            "items": [
+                                                {
+                                                    "pack": "pack_start",
+                                                    "xtype": "CellRendererText",
+                                                    "|xns": "Gtk"
+                                                }
+                                            ]
+                                        }
+                                    ]
+                                },
+                                {
+                                    "|xns": "Gtk",
+                                    "xtype": "TreeView",
+                                    "pack": false,
+                                    "items": [
+                                        {
+                                            "|xns": "Gtk",
+                                            "xtype": "ListStore",
+                                            "pack": false
+                                        }
+                                    ]
+                                }
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "id": "ok_button",
+                    "label": "Close",
+                    "pack": "add_action_widget,1",
+                    "xtype": "Button",
+                    "|xns": "Gtk"
+                }
+            ]
+        }
+    ],
+    "permname": "",
+    "modOrder": ""
+}
\ No newline at end of file
diff --git a/Clones.js b/Clones.js
new file mode 100644 (file)
index 0000000..553a8ad
--- /dev/null
+++ b/Clones.js
@@ -0,0 +1,549 @@
+Gtk = imports.gi.Gtk;
+Gdk = imports.gi.Gdk;
+Pango = imports.gi.Pango;
+GLib = imports.gi.GLib;
+Gio = imports.gi.Gio;
+GObject = imports.gi.GObject;
+GtkSource = imports.gi.GtkSource;
+WebKit = imports.gi.WebKit;
+Vte = imports.gi.Vte;
+console = imports.console;
+XObject = imports.XObject.XObject;
+Clones=new XObject({
+    xtype: Gtk.Dialog,
+    listeners : {
+        destroy_event : function (self, event) {
+              print("DESTROY?!");
+             return true;
+        },
+        response : function (self, id) {
+          // hide
+             //if (id < 1) {
+                this.el.hide();
+                return;
+            //}
+            if (typeof(this.get('bug').getValue()) != 'object') {
+                print("ERROR");
+                return;
+            }
+         
+            this.el.hide();
+                
+            //var val = this.get('bug').getValue();
+             //   Seed.print(val);
+        }
+    },
+    border_width : 3,
+    default_height : 500,
+    default_width : 600,
+    title : "Manage Clones",
+    deletable : true,
+    modal : true,
+    show : function(c) {
+        
+        if (!this.el) {
+            this.init();
+        }
+        var _this = this;
+        /*[ 'xtype'  ].forEach(function(k) {
+            _this.get(k).setValue(typeof(c[k]) == 'undefined' ? '' : c[k]);
+        });
+       // shouild set path..
+        */
+        this.el.set_deletable(false);
+        this.el.show_all();
+        // load clones..
+            this.get('/reposStore').load();
+        
+        //this.get('/ok_button').el.set_sensitive(false);
+        
+        // block until we return.
+        var run_ret = this.el.run();
+        if (run_ret < 1 ) {
+            return  "DONE";
+        }
+        print("RUN RETURN : " + run_ret);
+        return "DONE";
+        //print(JSON.stringify(this.get('bug').getValue()));
+       // return this.get('bug').getValue();
+        //this.success = c.success;
+    },
+    items : [
+        {
+            xtype: Gtk.VBox,
+            id : "Clones",
+            pack : function(p,e) {
+                    p.el.get_content_area().pack_start(e.el,true,true,0)
+                },
+            items : [
+                {
+                    xtype: Gtk.HBox,
+                    pack : "pack_start,false,true",
+                    items : [
+                        {
+                            xtype: Gtk.Button,
+                            listeners : {
+                                clicked : function (self) {
+                                
+                                    var rv = this.get('/reposView');
+                                    var rs = this.get('/reposStore');
+                                    if (rv.el.get_selection().count_selected_rows() != 1) {
+                                        //nothing?
+                                        // error condition.
+                                        return;
+                                    }
+                                    var Remotes =     imports.Remotes.Remotes;
+                                    
+                                 
+                                    var ret = {};       
+                                    var s = rv.el.get_selection();
+                                    var path = '';
+                                    s.selected_foreach(function(model,p,iter) {
+                                                                                    
+                                       path = model.get_value(iter, 6).value.get_string();
+                                     
+                                    }); 
+                                
+                                    var repo = false;
+                                    rs.repos.forEach(function(r) {
+                                        if (r.repopath == path) {
+                                            repo = r;
+                                        
+                                        }
+                                    
+                                    });
+                                    Remotes.repo = repo;
+                                    Remotes.el.set_transient_for(Clones.el);
+                                    Clones.el.set_title("Manage Clones - " + repo.repopath);
+                                    Remotes.show();
+                                    Clones.el.set_title("Manage Clones");
+                                
+                                     
+                                    
+                                    
+                                    
+                                
+                                       
+                                    
+                                    
+                                }
+                            },
+                            label : "Remotes / Clones",
+                            pack : "add"
+                        },
+                        {
+                            xtype: Gtk.Button,
+                            listeners : {
+                                clicked : function (self) {
+                                
+                                    var rv = this.get('/reposView');
+                                    var rs = this.get('/reposStore');
+                                    if (rv.el.get_selection().count_selected_rows() != 1) {
+                                        //nothing?
+                                        // error condition.
+                                        return;
+                                    }
+                                    var Branches =     imports.Branches.Branches;
+                                    
+                                 
+                                    var ret = {};       
+                                    var s = rv.el.get_selection();
+                                    var path = '';
+                                    s.selected_foreach(function(model,p,iter) {
+                                                                                    
+                                       path = model.get_value(iter, 6).value.get_string();
+                                     
+                                    }); 
+                                
+                                    var repo = false;
+                                    rs.repos.forEach(function(r) {
+                                        if (r.repopath == path) {
+                                            repo = r;
+                                        
+                                        }
+                                    
+                                    });
+                                    Branches.repo = repo;
+                                    Branches.el.set_transient_for(Clones.el);
+                                    Clones.el.set_title("Manage Clones - " + repo.repopath);
+                                    Branches.show();
+                                    Clones.el.set_title("Manage Clones");
+                                
+                                     
+                                    
+                                    
+                                    
+                                
+                                       
+                                    
+                                    
+                                }
+                            },
+                            label : "Branches",
+                            pack : "add"
+                        },
+                        {
+                            xtype: Gtk.Button,
+                            listeners : {
+                                clicked : function (self) {
+                                
+                                    var rv = this.get('/reposView');
+                                    var rs = this.get('/reposStore');
+                                    if (rv.el.get_selection().count_selected_rows() != 1) {
+                                        //nothing?
+                                        // error condition.
+                                        return;
+                                    }
+                                    var Merger =     imports.Merger.Merger;
+                                    
+                                 
+                                    var ret = {};       
+                                    var s = rv.el.get_selection();
+                                    var path = '';
+                                    s.selected_foreach(function(model,p,iter) {
+                                                                                    
+                                       path = model.get_value(iter, 6).value.get_string();
+                                     
+                                    }); 
+                                
+                                    var repo = false;
+                                    rs.repos.forEach(function(r) {
+                                        if (r.repopath == path) {
+                                            repo = r;
+                                        
+                                        }
+                                    
+                                    });
+                                    Merger.repo = repo;
+                                    Merger.el.set_transient_for(Clones.el);
+                                    Clones.el.set_title("Manage Clones - " + repo.repopath);
+                                    Merger.show();
+                                    Clones.el.set_title("Manage Clones");
+                                
+                                    
+                                    
+                                
+                                    
+                                
+                                    
+                                    
+                                    
+                                    
+                                
+                                       
+                                    
+                                    
+                                }
+                            },
+                            label : "Run Merger",
+                            pack : "add"
+                        },
+                        {
+                            xtype: Gtk.Button,
+                            listeners : {
+                                clicked : function (self) {
+                                    
+                                    
+                                 
+                                       
+                                    
+                                    
+                                }
+                            },
+                            label : "Switch Branch",
+                            pack : "add"
+                        },
+                        {
+                            xtype: Gtk.Button,
+                            listeners : {
+                                clicked : function (self) {
+                                    
+                                    
+                                 
+                                       
+                                    
+                                    
+                                }
+                            },
+                            label : "Pull",
+                            pack : "add"
+                        }
+                    ]
+                },
+                {
+                    xtype: Gtk.ScrolledWindow,
+                    init : function() {
+                        XObject.prototype.init.call(this);
+                          this.el.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
+                    },
+                    items : [
+                        {
+                            xtype: Gtk.TreeView,
+                            listeners : {
+                                cursor_changed : function (self) {
+                                  // SEE SELECTION.CHANGED
+                                  
+                                  
+                                  return;
+                                  
+                                    if (this.el.get_selection().count_selected_rows() < 1) {
+                                        //nothing? - clea it?
+                                        return;
+                                    }
+                                        var ret = {};         
+                                    var model = this.get('/changedFilesStore');
+                                
+                                     var s = this.el.get_selection();
+                                     var files = [];
+                                    s.selected_foreach(function(model,p,iter) {
+                                    
+                                       files.push( model.get_value(iter, 0).value.get_string());
+                                     
+                                    });
+                                    this.get('/patchview').showDiff(files); 
+                                    //var value = ''+ ret.model.get_value(ret.iter, 1).value.get_string();
+                                     //print("OUT?" + value);// id..
+                                    // load the list in the right grid..
+                                     
+                                    return true;
+                                
+                                }
+                            },
+                            id : "reposView",
+                            pack : "add",
+                            init : function() {
+                                XObject.prototype.init.call(this);
+                                    var description = new Pango.FontDescription.c_new();
+                               description.set_size(10000);
+                                 this.el.modify_font(description);
+                            
+                                 this.selection = this.el.get_selection();
+                                  this.selection.set_mode( Gtk.SelectionMode.MULTIPLE);
+                                var _this = this;
+                                
+                                
+                              this.selection.signal['changed'].connect(function() {
+                                 _this.listeners.cursor_changed.apply(
+                                      _this, [ _this, '']
+                                   );
+                                         });
+                              },
+                            items : [
+                                {
+                                    xtype: Gtk.ListStore,
+                                    id : "reposStore",
+                                    pack : "set_model",
+                                    init : function() {
+                                        XObject.prototype.init.call(this);
+                                        this.el.set_column_types ( 8, [
+                                           GObject.TYPE_STRING, // repo  
+                                          GObject.TYPE_STRING, // current branch
+                                          GObject.TYPE_STRING, // all branch      
+                                          GObject.TYPE_STRING, // updated
+                                           GObject.TYPE_BOOLEAN, // auto-commit
+                                            GObject.TYPE_BOOLEAN, // auto-push
+                                               GObject.TYPE_STRING, // repopath
+                                               GObject.TYPE_STRING // color highighling 
+                                      ] );
+                                    },
+                                    load : function()
+                                    {
+                                        //this.insert(citer,iter,0);
+                                        print("getting list");
+                                        this.repos = imports.Scm.Repo.Repo.list();
+                                        var tr= this.repos;
+                                        this.el.clear();
+                                        
+                                        for(var i =0 ; i < tr.length; i++) {
+                                            var ret = {  };
+                                           
+                                            this.el.append(ret);
+                                            
+                                            //print(JSON.stringify(ret,null,4));
+                                             tr[i].getBranches();
+                                             var hi;
+                                             try {
+                                                 //tr[i].debug=1;
+                                                  hi = tr[i].history('/', 1, 'branch', tr[i].currentBranch.name );
+                                    //             print(JSON.stringify(hi,null,4));
+                                             } catch(e) { print(e);}
+                                              
+                                            this.el.set_value(ret.iter, 0, '' +  tr[i].repopath.split('/').pop() );
+                                            this.el.set_value(ret.iter, 1, '' + tr[i].currentBranch.name   );
+                                            this.el.set_value(ret.iter, 2, '' + tr[i].branches.map(
+                                                            function(e) { return e.name; 
+                                                        }).join(', ') 
+                                             );
+                                            this.el.set_value(ret.iter, 3, '' +  (!hi  ? '??' : hi[0].changed_raw));        
+                                            this.el.set_value(ret.iter, 4, tr[i].autocommit() );                
+                                            this.el.set_value(ret.iter, 5, tr[i].autopush() );                        
+                                            this.el.set_value(ret.iter, 6,  tr[i].repopath );  
+                                            // highlight color.
+                                            var cb = tr[i].currentBranch;
+                                            //print(JSON.stringify(cb,null,4));
+                                            var col = cb.lastrev == cb.remoterev ? '#ffffff' : '#ff0000';
+                                            this.el.set_value(ret.iter, 7, col  );      
+                                            
+                                        }     
+                                    }
+                                },
+                                {
+                                    xtype: Gtk.TreeViewColumn,
+                                    min_width : 50,
+                                    pack : "append_column",
+                                    title : "Auto Commit",
+                                    init : function() {
+                                        XObject.prototype.init.call(this);
+                                        this.el.add_attribute(this.items[0].el , 'active', 4 );
+                                        this.items[0].el.set_activatable(true);
+                                    
+                                    },
+                                    items : [
+                                        {
+                                            xtype: Gtk.CellRendererToggle,
+                                            listeners : {
+                                                toggled : function (self, path) {
+                                                    var ret ={} ;
+                                                    var store = this.get('/reposStore');
+                                                    store.el.get_iter_from_string(ret, path);
+                                                                                                                 
+                                                    var value =   store.el.get_value(ret.iter,4).value.get_boolean();
+                                                                                                                 
+                                                    //print(JSON.stringify(value));
+                                                    store.el.set_value(ret.iter,4, !value);
+                                                    
+                                                }
+                                            },
+                                            pack : "pack_start",
+                                            mode : Gtk.CellRendererMode.ACTIVATABLE
+                                        }
+                                    ]
+                                },
+                                {
+                                    xtype: Gtk.TreeViewColumn,
+                                    min_width : 50,
+                                    pack : "append_column",
+                                    title : "Auto Push",
+                                    init : function() {
+                                        XObject.prototype.init.call(this);
+                                        this.el.add_attribute(this.items[0].el , 'active', 5 );
+                                          this.items[0].el.set_activatable(true);
+                                    },
+                                    items : [
+                                        {
+                                            xtype: Gtk.CellRendererToggle,
+                                            listeners : {
+                                                toggled : function (self, path) {
+                                                    var ret ={} ;
+                                                    var store = this.get('/reposStore');
+                                                    store.el.get_iter_from_string(ret, path);
+                                                                                                                 
+                                                    var value =   store.el.get_value(ret.iter,5).value.get_boolean();
+                                                                                                                 
+                                                    //print(JSON.stringify(value));
+                                                    store.el.set_value(ret.iter,5, !value);
+                                                    
+                                                }
+                                            },
+                                            pack : "pack_start",
+                                            mode : Gtk.CellRendererMode.ACTIVATABLE
+                                        }
+                                    ]
+                                },
+                                {
+                                    xtype: Gtk.TreeViewColumn,
+                                    min_width : 200,
+                                    pack : "append_column",
+                                    resizable : true,
+                                    title : "Repo",
+                                    init : function() {
+                                        XObject.prototype.init.call(this);
+                                        this.el.add_attribute(this.items[0].el , 'markup', 0 );
+                                    
+                                    },
+                                    items : [
+                                        {
+                                            xtype: Gtk.CellRendererText,
+                                            pack : "pack_start"
+                                        }
+                                    ]
+                                },
+                                {
+                                    xtype: Gtk.TreeViewColumn,
+                                    min_width : 50,
+                                    pack : "append_column",
+                                    title : "Current Branch",
+                                    init : function() {
+                                        XObject.prototype.init.call(this);
+                                        this.el.add_attribute(this.items[0].el , 'markup', 1 );
+                                         this.el.add_attribute(this.items[0].el , 'cell-background', 7 );
+                                    
+                                    },
+                                    items : [
+                                        {
+                                            xtype: Gtk.CellRendererText,
+                                            pack : "pack_start"
+                                        }
+                                    ]
+                                },
+                                {
+                                    xtype: Gtk.TreeViewColumn,
+                                    min_width : 50,
+                                    pack : "append_column",
+                                    title : "Last updated",
+                                    init : function() {
+                                        XObject.prototype.init.call(this);
+                                        this.el.add_attribute(this.items[0].el , 'markup', 3 );
+                                    
+                                    },
+                                    items : [
+                                        {
+                                            xtype: Gtk.CellRendererText,
+                                            pack : "pack_start"
+                                        }
+                                    ]
+                                },
+                                {
+                                    xtype: Gtk.TreeViewColumn,
+                                    min_width : 50,
+                                    pack : "append_column",
+                                    resizable : false,
+                                    title : "All Branches",
+                                    init : function() {
+                                        XObject.prototype.init.call(this);
+                                        this.el.add_attribute(this.items[0].el , 'markup', 2 );
+                                    
+                                    },
+                                    items : [
+                                        {
+                                            xtype: Gtk.CellRendererText,
+                                            pack : "pack_start"
+                                        }
+                                    ]
+                                }
+                            ]
+                        },
+                        {
+                            xtype: Gtk.TreeView,
+                            pack : false,
+                            items : [
+                                {
+                                    xtype: Gtk.ListStore,
+                                    pack : false
+                                }
+                            ]
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            xtype: Gtk.Button,
+            id : "ok_button",
+            label : "Close",
+            pack : "add_action_widget,1"
+        }
+    ]
+});
+Clones.init();
+XObject.cache['/Clones'] = Clones;
diff --git a/Commit.bjs b/Commit.bjs
new file mode 100644 (file)
index 0000000..b24740e
--- /dev/null
@@ -0,0 +1,161 @@
+{
+    "id": "file-gtk-3",
+    "name": "Commit",
+    "parent": "",
+    "title": false,
+    "path": "/home/alan/gitlive/gitlive/Commit.bjs",
+    "items": [
+        {
+            "listeners": {
+                "destroy_event": "function (self, event) {\n     this.el.hide();\n                return false;\n}",
+                "response": "function (self, id) {\n  // hide\n     //if (id < 1) {\n        this.el.hide();\n        return;\n    //}\n    if (typeof(this.get('bug').getValue()) != 'object') {\n        print(\"ERROR\");\n        return;\n    }\n \n    this.el.hide();\n        \n    //var val = this.get('bug').getValue();\n     //   Seed.print(val);\n}"
+            },
+            " modal": true,
+            "border_width": 3,
+            "default_height": 500,
+            "default_width": 800,
+            "title": "Commit",
+            "xtype": "Dialog",
+            "|deletable": "true",
+            "|modal": "true",
+            "|show": "function(c) {\n    \n    if (!this.el) {\n        this.init();\n    }\n    var _this = this;\n    \n    \n    this.files = c.files;\n    this.release = c.release;\n    this.rev = c.rev;\n    \n    this.repo = c.repo;\n\n    this.get('/commitDate').el.set_text(c.changed);\n    this.get('/commitAuthor').el.set_text(c.author);\n    this.get('/commitMsg').el.get_buffer().set_text('');\n    this.get('/commitPatch').showDiff(c.files);\n    \n    this.el.show_all();\n    \n    var run_ret = this.el.run();\n    if (run_ret < 1 ) {\n        return false;\n    }\n    var buf = this.get('/commitMsg').el.get_buffer();\n    var e = {};\n    var s = {};\n    buf.get_start_iter(s);\n    buf.get_end_iter(e);\n    \n    var ret=  {\n        date :  this.get('/commitDate').el.get_text(),\n        author :  this.get('/commitAuthor').el.get_text(),\n        message : buf.get_text(s.value, e.value, false)\n    };\n \n    return ret;\n    \n    \n    \n}\n",
+            "|xns": "Gtk",
+            "items": [
+                {
+                    "xtype": "VBox",
+                    "|pack": " function(p,e) {\n        p.el.get_content_area().pack_start(e.el,true,true,10);\n    }\n",
+                    "|xns": "Gtk",
+                    "items": [
+                        {
+                            "pack": "pack_start,false,true,2",
+                            "xtype": "HBox",
+                            "|xns": "Gtk",
+                            "items": [
+                                {
+                                    "label": "Fixes",
+                                    "pack": "pack_start,false,false,10",
+                                    "width_request": 50,
+                                    "xtype": "Label",
+                                    "|xns": "Gtk"
+                                },
+                                {
+                                    "listeners": {
+                                        "changed": "function (self) {\n   var val = this.el.get_child().get_text();\n   print(JSON.stringify(val));\n   if (!val.length) {\n       return;\n   }\n   \n   var name = this.get('/remoteName').el.get_text();\n   if (name.length) {\n       return;\n   }\n   // fill in name\n   var val = imports.Scm.Git.Repo.Repo.parseURL(val);\n   if ((typeof(val.host) != 'undefined') && val.host.length) {\n       var host = val.host;\n       // need to add github owner...\n        if (host.match(/github.com$/)) {\n          host += '.' + val.path.split('/').shift();\n        }\n   \n   \n        this.get('/remoteName').el.set_text(host);\n   }\n    \n   \n}"
+                                    },
+                                    "id": "commitFixes",
+                                    "xtype": "ComboBox",
+                                    "|init": "function() {\n    this.el = new Gtk.ComboBox.with_entry();\n    \n    \n    this.model  = new XObject(this.model);\n    this.model.init();\n    this.el.set_model(this.model.el);\n    this.el.set_entry_text_column (0);\n     XObject.prototype.init.call(this);\n    \n}\n",
+                                    "|load": "function(tr)\n{\n    //this.insert(citer,iter,0);\n    this.model.el.clear();\n    \n    var master = false;\n    var working = false;\n    \n    for(var i =0 ; i < tr.length; i++) {\n        var ret = {  };\n        this.model.el.append(ret);\n        //print(JSON.stringify(ret,null,4));\n        if (tr[i].name == 'master') {\n            master = i;\n        }\n        if (tr[i].name == 'working') {\n            working = i;\n        }          \n        this.model.el.set_value(ret.iter, 0, '' + tr[i].name );\n        this.model.el.set_value(ret.iter, 1, '' + tr[i].rev  );\n \n        \n    }     \n    if (master !== false) {\n        this.el.set_active(master);\n    }\n    if (working !== false) {\n        this.el.set_active(working);\n    }\n    \n}",
+                                    "|xns": "Gtk",
+                                    "items": [
+                                        {
+                                            "*prop": "model",
+                                            "xtype": "ListStore",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.set_column_types ( 3, [\n           GObject.TYPE_STRING, // file  \n          GObject.TYPE_STRING, // added\n          GObject.TYPE_STRING, // removed\n      ] );\n}\n",
+                                            "|xns": "Gtk"
+                                        }
+                                    ]
+                                }
+                            ]
+                        },
+                        {
+                            "pack": "pack_start,false,true,2",
+                            "xtype": "HBox",
+                            "|xns": "Gtk",
+                            "items": [
+                                {
+                                    "label": "Date",
+                                    "pack": "pack_start,false,false,10",
+                                    "width_request": 50,
+                                    "xalign": 1,
+                                    "xtype": "Label",
+                                    "|xns": "Gtk"
+                                },
+                                {
+                                    "id": "commitDate",
+                                    "xtype": "Entry",
+                                    "|xns": "Gtk"
+                                }
+                            ]
+                        },
+                        {
+                            "pack": "pack_start,false,true,2",
+                            "xtype": "HBox",
+                            "|xns": "Gtk",
+                            "items": [
+                                {
+                                    "label": "Author",
+                                    "pack": "pack_start,false,false,10",
+                                    "width_request": 50,
+                                    "xalign": 1,
+                                    "xtype": "Label",
+                                    "|xns": "Gtk"
+                                },
+                                {
+                                    "id": "commitAuthor",
+                                    "xtype": "Entry",
+                                    "|xns": "Gtk"
+                                }
+                            ]
+                        },
+                        {
+                            "pack": "pack_start,false,false,2",
+                            "xtype": "HBox",
+                            "|xns": "Gtk",
+                            "items": [
+                                {
+                                    "label": "Message",
+                                    "pack": "pack_start,false,false,10",
+                                    "width_request": 50,
+                                    "xalign": 1,
+                                    "xtype": "Label",
+                                    "|xns": "Gtk"
+                                },
+                                {
+                                    "height_request": 100,
+                                    "id": "commitMsg",
+                                    "pack": "add",
+                                    "xtype": "TextView",
+                                    "|xns": "Gtk"
+                                }
+                            ]
+                        },
+                        {
+                            "height_request": 200,
+                            "pack": "pack_end,true,true,0",
+                            "xtype": "ScrolledWindow",
+                            "|init": "function() {\n    XObject.prototype.init.call(this);\n      this.el.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)\n}\n",
+                            "|xns": "Gtk",
+                            "items": [
+                                {
+                                    "id": "commitPatch",
+                                    "pack": "add",
+                                    "xtype": "WebView",
+                                    "|clear": "function() {\n    \n    \n    \n     \n   // remove..\n    var s  = \"document.body.textContent='';\"\n        \n    this.el.execute_script(s);\n        \n        \n    \n    \n    \n}\n",
+                                    "|showDiff": "function(files) {\n    this.clear();\n    \n    \n    \n    if (Commit.release === false) {\n        return;\n    }\n    \n    var diff = Commit.repo.diff(files, Commit.release, Commit.rev);\n    \n   // remove..\n    var s  = \"var pre  = document.createElement('pre'); document.body.appendChild(pre);\";\n    s += \"pre.textContent =  \" +\n             JSON.stringify(Commit.repo.lastCmd + \"\\n\") + '+  ' + \n             JSON.stringify(diff) + \";\";\n        \n    this.el.execute_script(s);\n        \n        \n    \n    \n    \n}\n",
+                                    "|xns": "WebKit"
+                                }
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "label": "Cancel",
+                    "pack": "add_action_widget,0",
+                    "xtype": "Button",
+                    "|xns": "Gtk",
+                    "listeners": {}
+                },
+                {
+                    "id": "ok_button",
+                    "label": "Add",
+                    "pack": "add_action_widget,1",
+                    "xtype": "Button",
+                    "|xns": "Gtk"
+                }
+            ]
+        }
+    ],
+    "permname": "",
+    "modOrder": ""
+}
\ No newline at end of file
diff --git a/Commit.js b/Commit.js
new file mode 100644 (file)
index 0000000..e56a48e
--- /dev/null
+++ b/Commit.js
@@ -0,0 +1,313 @@
+Gtk = imports.gi.Gtk;
+Gdk = imports.gi.Gdk;
+Pango = imports.gi.Pango;
+GLib = imports.gi.GLib;
+Gio = imports.gi.Gio;
+GObject = imports.gi.GObject;
+GtkSource = imports.gi.GtkSource;
+WebKit = imports.gi.WebKit;
+Vte = imports.gi.Vte;
+console = imports.console;
+XObject = imports.XObject.XObject;
+Commit=new XObject({
+    xtype: Gtk.Dialog,
+    listeners : {
+        destroy_event : function (self, event) {
+             this.el.hide();
+                        return false;
+        },
+        response : function (self, id) {
+          // hide
+             //if (id < 1) {
+                this.el.hide();
+                return;
+            //}
+            if (typeof(this.get('bug').getValue()) != 'object') {
+                print("ERROR");
+                return;
+            }
+         
+            this.el.hide();
+                
+            //var val = this.get('bug').getValue();
+             //   Seed.print(val);
+        }
+    },
+    ' modal' : true,
+    border_width : 3,
+    default_height : 500,
+    default_width : 800,
+    title : "Commit",
+    deletable : true,
+    modal : true,
+    show : function(c) {
+        
+        if (!this.el) {
+            this.init();
+        }
+        var _this = this;
+        
+        
+        this.files = c.files;
+        this.release = c.release;
+        this.rev = c.rev;
+        
+        this.repo = c.repo;
+    
+        this.get('/commitDate').el.set_text(c.changed);
+        this.get('/commitAuthor').el.set_text(c.author);
+        this.get('/commitMsg').el.get_buffer().set_text('');
+        this.get('/commitPatch').showDiff(c.files);
+        
+        this.el.show_all();
+        
+        var run_ret = this.el.run();
+        if (run_ret < 1 ) {
+            return false;
+        }
+        var buf = this.get('/commitMsg').el.get_buffer();
+        var e = {};
+        var s = {};
+        buf.get_start_iter(s);
+        buf.get_end_iter(e);
+        
+        var ret=  {
+            date :  this.get('/commitDate').el.get_text(),
+            author :  this.get('/commitAuthor').el.get_text(),
+            message : buf.get_text(s.value, e.value, false)
+        };
+     
+        return ret;
+        
+        
+        
+    },
+    items : [
+        {
+            xtype: Gtk.VBox,
+            pack : function(p,e) {
+                    p.el.get_content_area().pack_start(e.el,true,true,10);
+                },
+            items : [
+                {
+                    xtype: Gtk.HBox,
+                    pack : "pack_start,false,true,2",
+                    items : [
+                        {
+                            xtype: Gtk.Label,
+                            label : "Fixes",
+                            pack : "pack_start,false,false,10",
+                            width_request : 50
+                        },
+                        {
+                            xtype: Gtk.ComboBox,
+                            listeners : {
+                                changed : function (self) {
+                                   var val = this.el.get_child().get_text();
+                                   print(JSON.stringify(val));
+                                   if (!val.length) {
+                                       return;
+                                   }
+                                   
+                                   var name = this.get('/remoteName').el.get_text();
+                                   if (name.length) {
+                                       return;
+                                   }
+                                   // fill in name
+                                   var val = imports.Scm.Git.Repo.Repo.parseURL(val);
+                                   if ((typeof(val.host) != 'undefined') && val.host.length) {
+                                       var host = val.host;
+                                       // need to add github owner...
+                                        if (host.match(/github.com$/)) {
+                                          host += '.' + val.path.split('/').shift();
+                                        }
+                                   
+                                   
+                                        this.get('/remoteName').el.set_text(host);
+                                   }
+                                    
+                                   
+                                }
+                            },
+                            id : "commitFixes",
+                            init : function() {
+                                this.el = new Gtk.ComboBox.with_entry();
+                                
+                                
+                                this.model  = new XObject(this.model);
+                                this.model.init();
+                                this.el.set_model(this.model.el);
+                                this.el.set_entry_text_column (0);
+                                 XObject.prototype.init.call(this);
+                                
+                            },
+                            load : function(tr)
+                            {
+                                //this.insert(citer,iter,0);
+                                this.model.el.clear();
+                                
+                                var master = false;
+                                var working = false;
+                                
+                                for(var i =0 ; i < tr.length; i++) {
+                                    var ret = {  };
+                                    this.model.el.append(ret);
+                                    //print(JSON.stringify(ret,null,4));
+                                    if (tr[i].name == 'master') {
+                                        master = i;
+                                    }
+                                    if (tr[i].name == 'working') {
+                                        working = i;
+                                    }          
+                                    this.model.el.set_value(ret.iter, 0, '' + tr[i].name );
+                                    this.model.el.set_value(ret.iter, 1, '' + tr[i].rev  );
+                             
+                                    
+                                }     
+                                if (master !== false) {
+                                    this.el.set_active(master);
+                                }
+                                if (working !== false) {
+                                    this.el.set_active(working);
+                                }
+                                
+                            },
+                            model : {
+                                xtype: Gtk.ListStore,
+                                init : function() {
+                                    XObject.prototype.init.call(this);
+                                    this.el.set_column_types ( 3, [
+                                           GObject.TYPE_STRING, // file  
+                                          GObject.TYPE_STRING, // added
+                                          GObject.TYPE_STRING, // removed
+                                      ] );
+                                }
+                            }
+                        }
+                    ]
+                },
+                {
+                    xtype: Gtk.HBox,
+                    pack : "pack_start,false,true,2",
+                    items : [
+                        {
+                            xtype: Gtk.Label,
+                            label : "Date",
+                            pack : "pack_start,false,false,10",
+                            width_request : 50,
+                            xalign : 1
+                        },
+                        {
+                            xtype: Gtk.Entry,
+                            id : "commitDate"
+                        }
+                    ]
+                },
+                {
+                    xtype: Gtk.HBox,
+                    pack : "pack_start,false,true,2",
+                    items : [
+                        {
+                            xtype: Gtk.Label,
+                            label : "Author",
+                            pack : "pack_start,false,false,10",
+                            width_request : 50,
+                            xalign : 1
+                        },
+                        {
+                            xtype: Gtk.Entry,
+                            id : "commitAuthor"
+                        }
+                    ]
+                },
+                {
+                    xtype: Gtk.HBox,
+                    pack : "pack_start,false,false,2",
+                    items : [
+                        {
+                            xtype: Gtk.Label,
+                            label : "Message",
+                            pack : "pack_start,false,false,10",
+                            width_request : 50,
+                            xalign : 1
+                        },
+                        {
+                            xtype: Gtk.TextView,
+                            height_request : 100,
+                            id : "commitMsg",
+                            pack : "add"
+                        }
+                    ]
+                },
+                {
+                    xtype: Gtk.ScrolledWindow,
+                    height_request : 200,
+                    pack : "pack_end,true,true,0",
+                    init : function() {
+                        XObject.prototype.init.call(this);
+                          this.el.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
+                    },
+                    items : [
+                        {
+                            xtype: WebKit.WebView,
+                            id : "commitPatch",
+                            pack : "add",
+                            clear : function() {
+                                
+                                
+                                
+                                 
+                               // remove..
+                                var s  = "document.body.textContent='';"
+                                    
+                                this.el.execute_script(s);
+                                    
+                                    
+                                
+                                
+                                
+                            },
+                            showDiff : function(files) {
+                                this.clear();
+                                
+                                
+                                
+                                if (Commit.release === false) {
+                                    return;
+                                }
+                                
+                                var diff = Commit.repo.diff(files, Commit.release, Commit.rev);
+                                
+                               // remove..
+                                var s  = "var pre  = document.createElement('pre'); document.body.appendChild(pre);";
+                                s += "pre.textContent =  " +
+                                         JSON.stringify(Commit.repo.lastCmd + "\n") + '+  ' + 
+                                         JSON.stringify(diff) + ";";
+                                    
+                                this.el.execute_script(s);
+                                    
+                                    
+                                
+                                
+                                
+                            }
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            xtype: Gtk.Button,
+            label : "Cancel",
+            pack : "add_action_widget,0"
+        },
+        {
+            xtype: Gtk.Button,
+            id : "ok_button",
+            label : "Add",
+            pack : "add_action_widget,1"
+        }
+    ]
+});
+Commit.init();
+XObject.cache['/Commit'] = Commit;
diff --git a/Date.js b/Date.js
new file mode 100644 (file)
index 0000000..aff4700
--- /dev/null
+++ b/Date.js
@@ -0,0 +1,835 @@
+/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+
+/**
+ * @class Date
+ *
+ * The date parsing and format syntax is a subset of
+ * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
+ * supported will provide results equivalent to their PHP versions.
+ *
+ * Following is the list of all currently supported formats:
+ *<pre>
+Sample date:
+'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
+
+Format  Output      Description
+------  ----------  --------------------------------------------------------------
+  d      10         Day of the month, 2 digits with leading zeros
+  D      Wed        A textual representation of a day, three letters
+  j      10         Day of the month without leading zeros
+  l      Wednesday  A full textual representation of the day of the week
+  S      th         English ordinal day of month suffix, 2 chars (use with j)
+  w      3          Numeric representation of the day of the week
+  z      9          The julian date, or day of the year (0-365)
+  W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
+  F      January    A full textual representation of the month
+  m      01         Numeric representation of a month, with leading zeros
+  M      Jan        Month name abbreviation, three letters
+  n      1          Numeric representation of a month, without leading zeros
+  t      31         Number of days in the given month
+  L      0          Whether it's a leap year (1 if it is a leap year, else 0)
+  Y      2007       A full numeric representation of a year, 4 digits
+  y      07         A two digit representation of a year
+  a      pm         Lowercase Ante meridiem and Post meridiem
+  A      PM         Uppercase Ante meridiem and Post meridiem
+  g      3          12-hour format of an hour without leading zeros
+  G      15         24-hour format of an hour without leading zeros
+  h      03         12-hour format of an hour with leading zeros
+  H      15         24-hour format of an hour with leading zeros
+  i      05         Minutes with leading zeros
+  s      01         Seconds, with leading zeros
+  O      -0600      Difference to Greenwich time (GMT) in hours
+  P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
+  T      CST        Timezone setting of the machine running the code
+  Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
+</pre>
+ *
+ * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
+ * <pre><code>
+var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
+document.write(dt.format('Y-m-d'));                         //2007-01-10
+document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
+document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
+ </code></pre>
+ *
+ * Here are some standard date/time patterns that you might find helpful.  They
+ * are not part of the source of Date.js, but to use them you can simply copy this
+ * block of code into any script that is included after Date.js and they will also become
+ * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
+ * <pre><code>
+Date.patterns = {
+    ISO8601Long:"Y-m-d H:i:s",
+    ISO8601Short:"Y-m-d",
+    ShortDate: "n/j/Y",
+    LongDate: "l, F d, Y",
+    FullDateTime: "l, F d, Y g:i:s A",
+    MonthDay: "F d",
+    ShortTime: "g:i A",
+    LongTime: "g:i:s A",
+    SortableDateTime: "Y-m-d\\TH:i:s",
+    UniversalSortableDateTime: "Y-m-d H:i:sO",
+    YearMonth: "F, Y"
+};
+</code></pre>
+ *
+ * Example usage:
+ * <pre><code>
+var dt = new Date();
+document.write(dt.format(Date.patterns.ShortDate));
+ </code></pre>
+ */
+
+/*
+ * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
+ * They generate precompiled functions from date formats instead of parsing and
+ * processing the pattern every time you format a date.  These functions are available
+ * on every Date object (any javascript function).
+ *
+ * The original article and download are here:
+ * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
+ *
+ */
+ // was in core
+/**
+ Returns the number of milliseconds between this date and date
+ @param {Date} date (optional) Defaults to now
+ @return {Number} The diff in milliseconds
+ @member Date getElapsed
+ */
+Date.prototype.getElapsed = function(date) {
+       return Math.abs((date || new Date()).getTime()-this.getTime());
+};
+// was in date file..
+
+
+// private
+Date.parseFunctions = {count:0};
+// private
+Date.parseRegexes = [];
+// private
+Date.formatFunctions = {count:0};
+
+
+
+Date.escape  = function(string) {
+        return string.replace(/('|\\)/g, "\\$1");
+};
+
+  
+Date.leftPad = function (val, size, ch) {
+    var result = new String(val);
+    if(ch === null || ch === undefined || ch === '') {
+        ch = " ";
+    }
+    while (result.length < size) {
+        result = ch + result;
+    }
+    return result;
+}
+
+
+
+
+
+
+
+
+
+
+
+// private
+Date.prototype.dateFormat = function(format) {
+    if (Date.formatFunctions[format] == null) {
+        Date.createNewFormat(format);
+    }
+    var func = Date.formatFunctions[format];
+    return this[func]();
+};
+
+
+/**
+ * Formats a date given the supplied format string
+ * @param {String} format The format string
+ * @return {String} The formatted date
+ * @method
+ */
+Date.prototype.format = Date.prototype.dateFormat;
+
+// private
+Date.createNewFormat = function(format) {
+    var funcName = "format" + Date.formatFunctions.count++;
+    Date.formatFunctions[format] = funcName;
+    var code = "Date.prototype." + funcName + " = function(){return ";
+    var special = false;
+    var ch = '';
+    for (var i = 0; i < format.length; ++i) {
+        ch = format.charAt(i);
+        if (!special && ch == "\\") {
+            special = true;
+        }
+        else if (special) {
+            special = false;
+            code += "'" + Date.escape(ch) + "' + ";
+        }
+        else {
+            code += Date.getFormatCode(ch);
+        }
+    }
+    /** eval:var:zzzzzzzzzzzzz */
+    eval(code.substring(0, code.length - 3) + ";}");
+};
+
+// private
+Date.getFormatCode = function(character) {
+    switch (character) {
+    case "d":
+        return "Date.leftPad(this.getDate(), 2, '0') + ";
+    case "D":
+        return "Date.dayNames[this.getDay()].substring(0, 3) + ";
+    case "j":
+        return "this.getDate() + ";
+    case "l":
+        return "Date.dayNames[this.getDay()] + ";
+    case "S":
+        return "this.getSuffix() + ";
+    case "w":
+        return "this.getDay() + ";
+    case "z":
+        return "this.getDayOfYear() + ";
+    case "W":
+        return "this.getWeekOfYear() + ";
+    case "F":
+        return "Date.monthNames[this.getMonth()] + ";
+    case "m":
+        return "Date.leftPad(this.getMonth() + 1, 2, '0') + ";
+    case "M":
+        return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
+    case "n":
+        return "(this.getMonth() + 1) + ";
+    case "t":
+        return "this.getDaysInMonth() + ";
+    case "L":
+        return "(this.isLeapYear() ? 1 : 0) + ";
+    case "Y":
+        return "this.getFullYear() + ";
+    case "y":
+        return "('' + this.getFullYear()).substring(2, 4) + ";
+    case "a":
+        return "(this.getHours() < 12 ? 'am' : 'pm') + ";
+    case "A":
+        return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
+    case "g":
+        return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
+    case "G":
+        return "this.getHours() + ";
+    case "h":
+        return "Date.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
+    case "H":
+        return "Date.leftPad(this.getHours(), 2, '0') + ";
+    case "i":
+        return "Date.leftPad(this.getMinutes(), 2, '0') + ";
+    case "s":
+        return "Date.leftPad(this.getSeconds(), 2, '0') + ";
+    case "O":
+        return "this.getGMTOffset() + ";
+    case "P":
+       return "this.getGMTColonOffset() + ";
+    case "T":
+        return "this.getTimezone() + ";
+    case "Z":
+        return "(this.getTimezoneOffset() * -60) + ";
+    default:
+        return "'" + Date.escape(character) + "' + ";
+    }
+};
+
+/**
+ * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
+ * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
+ * the date format that is not specified will default to the current date value for that part.  Time parts can also
+ * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
+ * string or the parse operation will fail.
+ * Example Usage:
+<pre><code>
+//dt = Fri May 25 2007 (current date)
+var dt = new Date();
+
+//dt = Thu May 25 2006 (today's month/day in 2006)
+dt = Date.parseDate("2006", "Y");
+
+//dt = Sun Jan 15 2006 (all date parts specified)
+dt = Date.parseDate("2006-1-15", "Y-m-d");
+
+//dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
+dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
+</code></pre>
+ * @param {String} input The unparsed date as a string
+ * @param {String} format The format the date is in
+ * @return {Date} The parsed date
+ * @static
+ */
+Date.parseDate = function(input, format) {
+    if (Date.parseFunctions[format] == null) {
+        Date.createParser(format);
+    }
+    var func = Date.parseFunctions[format];
+    return Date[func](input);
+};
+/**
+ * @private
+ */
+Date.createParser = function(format) {
+    var funcName = "parse" + Date.parseFunctions.count++;
+    var regexNum = Date.parseRegexes.length;
+    var currentGroup = 1;
+    Date.parseFunctions[format] = funcName;
+
+    var code = "Date." + funcName + " = function(input){\n"
+        + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
+        + "var d = new Date();\n"
+        + "y = d.getFullYear();\n"
+        + "m = d.getMonth();\n"
+        + "d = d.getDate();\n"
+        + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
+        + "if (results && results.length > 0) {";
+    var regex = "";
+
+    var special = false;
+    var ch = '';
+    for (var i = 0; i < format.length; ++i) {
+        ch = format.charAt(i);
+        if (!special && ch == "\\") {
+            special = true;
+        }
+        else if (special) {
+            special = false;
+            regex += Date.escape(ch);
+        }
+        else {
+            var obj = Date.formatCodeToRegex(ch, currentGroup);
+            currentGroup += obj.g;
+            regex += obj.s;
+            if (obj.g && obj.c) {
+                code += obj.c;
+            }
+        }
+    }
+
+    code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
+        + "{v = new Date(y, m, d, h, i, s);}\n"
+        + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
+        + "{v = new Date(y, m, d, h, i);}\n"
+        + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
+        + "{v = new Date(y, m, d, h);}\n"
+        + "else if (y >= 0 && m >= 0 && d > 0)\n"
+        + "{v = new Date(y, m, d);}\n"
+        + "else if (y >= 0 && m >= 0)\n"
+        + "{v = new Date(y, m);}\n"
+        + "else if (y >= 0)\n"
+        + "{v = new Date(y);}\n"
+        + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
+        + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
+        + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
+        + ";}";
+
+    Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
+    /** eval:var:zzzzzzzzzzzzz */
+    eval(code);
+};
+
+// private
+Date.formatCodeToRegex = function(character, currentGroup) {
+    switch (character) {
+    case "D":
+        return {g:0,
+        c:null,
+        s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
+    case "j":
+        return {g:1,
+            c:"d = parseInt(results[" + currentGroup + "], 10);\n",
+            s:"(\\d{1,2})"}; // day of month without leading zeroes
+    case "d":
+        return {g:1,
+            c:"d = parseInt(results[" + currentGroup + "], 10);\n",
+            s:"(\\d{2})"}; // day of month with leading zeroes
+    case "l":
+        return {g:0,
+            c:null,
+            s:"(?:" + Date.dayNames.join("|") + ")"};
+    case "S":
+        return {g:0,
+            c:null,
+            s:"(?:st|nd|rd|th)"};
+    case "w":
+        return {g:0,
+            c:null,
+            s:"\\d"};
+    case "z":
+        return {g:0,
+            c:null,
+            s:"(?:\\d{1,3})"};
+    case "W":
+        return {g:0,
+            c:null,
+            s:"(?:\\d{2})"};
+    case "F":
+        return {g:1,
+            c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
+            s:"(" + Date.monthNames.join("|") + ")"};
+    case "M":
+        return {g:1,
+            c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
+            s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
+    case "n":
+        return {g:1,
+            c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
+            s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
+    case "m":
+        return {g:1,
+            c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
+            s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
+    case "t":
+        return {g:0,
+            c:null,
+            s:"\\d{1,2}"};
+    case "L":
+        return {g:0,
+            c:null,
+            s:"(?:1|0)"};
+    case "Y":
+        return {g:1,
+            c:"y = parseInt(results[" + currentGroup + "], 10);\n",
+            s:"(\\d{4})"};
+    case "y":
+        return {g:1,
+            c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
+                + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
+            s:"(\\d{1,2})"};
+    case "a":
+        return {g:1,
+            c:"if (results[" + currentGroup + "] == 'am') {\n"
+                + "if (h == 12) { h = 0; }\n"
+                + "} else { if (h < 12) { h += 12; }}",
+            s:"(am|pm)"};
+    case "A":
+        return {g:1,
+            c:"if (results[" + currentGroup + "] == 'AM') {\n"
+                + "if (h == 12) { h = 0; }\n"
+                + "} else { if (h < 12) { h += 12; }}",
+            s:"(AM|PM)"};
+    case "g":
+    case "G":
+        return {g:1,
+            c:"h = parseInt(results[" + currentGroup + "], 10);\n",
+            s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
+    case "h":
+    case "H":
+        return {g:1,
+            c:"h = parseInt(results[" + currentGroup + "], 10);\n",
+            s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
+    case "i":
+        return {g:1,
+            c:"i = parseInt(results[" + currentGroup + "], 10);\n",
+            s:"(\\d{2})"};
+    case "s":
+        return {g:1,
+            c:"s = parseInt(results[" + currentGroup + "], 10);\n",
+            s:"(\\d{2})"};
+    case "O":
+        return {g:1,
+            c:[
+                "o = results[", currentGroup, "];\n",
+                "var sn = o.substring(0,1);\n", // get + / - sign
+                "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
+                "var mn = o.substring(3,5) % 60;\n", // get minutes
+                "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
+                "    (sn + Date.leftPad(hr, 2, 0) + Date.leftPad(mn, 2, 0)) : null;\n"
+            ].join(""),
+            s:"([+\-]\\d{4})"};
+    case "P":
+       return {g:1,
+               c:[
+                  "o = results[", currentGroup, "];\n",
+                  "var sn = o.substring(0,1);\n",
+                  "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
+                  "var mn = o.substring(4,6) % 60;\n",
+                  "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
+                       "    (sn + Date.leftPad(hr, 2, 0) + Date.leftPad(mn, 2, 0)) : null;\n"
+            ].join(""),
+            s:"([+\-]\\d{4})"};
+    case "T":
+        return {g:0,
+            c:null,
+            s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
+    case "Z":
+        return {g:1,
+            c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
+                  + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
+            s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
+    default:
+        return {g:0,
+            c:null,
+            s:Date.escape(character)};
+    }
+};
+
+/**
+ * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
+ * @return {String} The abbreviated timezone name (e.g. 'CST')
+ */
+Date.prototype.getTimezone = function() {
+    return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
+};
+
+/**
+ * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
+ */
+Date.prototype.getGMTOffset = function() {
+    return (this.getTimezoneOffset() > 0 ? "-" : "+")
+        + Date.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
+        + Date.leftPad(this.getTimezoneOffset() % 60, 2, "0");
+};
+
+/**
+ * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
+ * @return {String} 2-characters representing hours and 2-characters representing minutes
+ * seperated by a colon and prefixed with + or - (e.g. '-06:00')
+ */
+Date.prototype.getGMTColonOffset = function() {
+       return (this.getTimezoneOffset() > 0 ? "-" : "+")
+               + Date.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
+               + ":"
+               + Date.leftPad(this.getTimezoneOffset() %60, 2, "0");
+}
+
+/**
+ * Get the numeric day number of the year, adjusted for leap year.
+ * @return {Number} 0 through 364 (365 in leap years)
+ */
+Date.prototype.getDayOfYear = function() {
+    var num = 0;
+    Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
+    for (var i = 0; i < this.getMonth(); ++i) {
+        num += Date.daysInMonth[i];
+    }
+    return num + this.getDate() - 1;
+};
+
+/**
+ * Get the string representation of the numeric week number of the year
+ * (equivalent to the format specifier 'W').
+ * @return {String} '00' through '52'
+ */
+Date.prototype.getWeekOfYear = function() {
+    // Skip to Thursday of this week
+    var now = this.getDayOfYear() + (4 - this.getDay());
+    // Find the first Thursday of the year
+    var jan1 = new Date(this.getFullYear(), 0, 1);
+    var then = (7 - jan1.getDay() + 4);
+    return Date.leftPad(((now - then) / 7) + 1, 2, "0");
+};
+
+/**
+ * Whether or not the current date is in a leap year.
+ * @return {Boolean} True if the current date is in a leap year, else false
+ */
+Date.prototype.isLeapYear = function() {
+    var year = this.getFullYear();
+    return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
+};
+
+/**
+ * Get the first day of the current month, adjusted for leap year.  The returned value
+ * is the numeric day index within the week (0-6) which can be used in conjunction with
+ * the {@link #monthNames} array to retrieve the textual day name.
+ * Example:
+ *<pre><code>
+var dt = new Date('1/10/2007');
+document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
+</code></pre>
+ * @return {Number} The day number (0-6)
+ */
+Date.prototype.getFirstDayOfMonth = function() {
+    var day = (this.getDay() - (this.getDate() - 1)) % 7;
+    return (day < 0) ? (day + 7) : day;
+};
+
+/**
+ * Get the last day of the current month, adjusted for leap year.  The returned value
+ * is the numeric day index within the week (0-6) which can be used in conjunction with
+ * the {@link #monthNames} array to retrieve the textual day name.
+ * Example:
+ *<pre><code>
+var dt = new Date('1/10/2007');
+document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
+</code></pre>
+ * @return {Number} The day number (0-6)
+ */
+Date.prototype.getLastDayOfMonth = function() {
+    var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
+    return (day < 0) ? (day + 7) : day;
+};
+
+
+/**
+ * Get the first date of this date's month
+ * @return {Date}
+ */
+Date.prototype.getFirstDateOfMonth = function() {
+    return new Date(this.getFullYear(), this.getMonth(), 1);
+};
+
+/**
+ * Get the last date of this date's month
+ * @return {Date}
+ */
+Date.prototype.getLastDateOfMonth = function() {
+    return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
+};
+/**
+ * Get the number of days in the current month, adjusted for leap year.
+ * @return {Number} The number of days in the month
+ */
+Date.prototype.getDaysInMonth = function() {
+    Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
+    return Date.daysInMonth[this.getMonth()];
+};
+
+/**
+ * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
+ * @return {String} 'st, 'nd', 'rd' or 'th'
+ */
+Date.prototype.getSuffix = function() {
+    switch (this.getDate()) {
+        case 1:
+        case 21:
+        case 31:
+            return "st";
+        case 2:
+        case 22:
+            return "nd";
+        case 3:
+        case 23:
+            return "rd";
+        default:
+            return "th";
+    }
+};
+
+// private
+Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
+
+/**
+ * An array of textual month names.
+ * Override these values for international dates, for example...
+ * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
+ * @type Array
+ * @static
+ */
+Date.monthNames =
+   ["January",
+    "February",
+    "March",
+    "April",
+    "May",
+    "June",
+    "July",
+    "August",
+    "September",
+    "October",
+    "November",
+    "December"];
+
+/**
+ * An array of textual day names.
+ * Override these values for international dates, for example...
+ * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
+ * @type Array
+ * @static
+ */
+Date.dayNames =
+   ["Sunday",
+    "Monday",
+    "Tuesday",
+    "Wednesday",
+    "Thursday",
+    "Friday",
+    "Saturday"];
+
+// private
+Date.y2kYear = 50;
+// private
+Date.monthNumbers = {
+    Jan:0,
+    Feb:1,
+    Mar:2,
+    Apr:3,
+    May:4,
+    Jun:5,
+    Jul:6,
+    Aug:7,
+    Sep:8,
+    Oct:9,
+    Nov:10,
+    Dec:11};
+
+/**
+ * Creates and returns a new Date instance with the exact same date value as the called instance.
+ * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
+ * variable will also be changed.  When the intention is to create a new variable that will not
+ * modify the original instance, you should create a clone.
+ *
+ * Example of correctly cloning a date:
+ * <pre><code>
+//wrong way:
+var orig = new Date('10/1/2006');
+var copy = orig;
+copy.setDate(5);
+document.write(orig);  //returns 'Thu Oct 05 2006'!
+
+//correct way:
+var orig = new Date('10/1/2006');
+var copy = orig.clone();
+copy.setDate(5);
+document.write(orig);  //returns 'Thu Oct 01 2006'
+</code></pre>
+ * @return {Date} The new Date instance
+ */
+Date.prototype.clone = function() {
+       return new Date(this.getTime());
+};
+
+/**
+ * Clears any time information from this date
+ @param {Boolean} clone true to create a clone of this date, clear the time and return it
+ @return {Date} this or the clone
+ */
+Date.prototype.clearTime = function(clone){
+    if(clone){
+        return this.clone().clearTime();
+    }
+    this.setHours(0);
+    this.setMinutes(0);
+    this.setSeconds(0);
+    this.setMilliseconds(0);
+    return this;
+};
+
+// private
+// safari setMonth is broken
+/*
+if(Roo.isSafari){
+    Date.brokenSetMonth = Date.prototype.setMonth;
+       Date.prototype.setMonth = function(num){
+               if(num <= -1){
+                       var n = Math.ceil(-num);
+                       var back_year = Math.ceil(n/12);
+                       var month = (n % 12) ? 12 - n % 12 : 0 ;
+                       this.setFullYear(this.getFullYear() - back_year);
+                       return Date.brokenSetMonth.call(this, month);
+               } else {
+                       return Date.brokenSetMonth.apply(this, arguments);
+               }
+       };
+}
+*/
+
+/** Date interval constant 
+* @static 
+* @type String */
+Date.MILLI = "ms";
+/** Date interval constant 
+* @static 
+* @type String */
+Date.SECOND = "s";
+/** Date interval constant 
+* @static 
+* @type String */
+Date.MINUTE = "mi";
+/** Date interval constant 
+* @static 
+* @type String */
+Date.HOUR = "h";
+/** Date interval constant 
+* @static 
+* @type String */
+Date.DAY = "d";
+/** Date interval constant 
+* @static 
+* @type String */
+Date.MONTH = "mo";
+/** Date interval constant 
+* @static 
+* @type String */
+Date.YEAR = "y";
+
+/**
+ * Provides a convenient method of performing basic date arithmetic.  This method
+ * does not modify the Date instance being called - it creates and returns
+ * a new Date instance containing the resulting date value.
+ *
+ * Examples:
+ * <pre><code>
+//Basic usage:
+var dt = new Date('10/29/2006').add(Date.DAY, 5);
+document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
+
+//Negative values will subtract correctly:
+var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
+document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
+
+//You can even chain several calls together in one line!
+var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
+document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
+ </code></pre>
+ *
+ * @param {String} interval   A valid date interval enum value
+ * @param {Number} value      The amount to add to the current date
+ * @return {Date} The new Date instance
+ */
+Date.prototype.add = function(interval, value){
+  var d = this.clone();
+  if (!interval || value === 0) return d;
+  switch(interval.toLowerCase()){
+    case Date.MILLI:
+      d.setMilliseconds(this.getMilliseconds() + value);
+      break;
+    case Date.SECOND:
+      d.setSeconds(this.getSeconds() + value);
+      break;
+    case Date.MINUTE:
+      d.setMinutes(this.getMinutes() + value);
+      break;
+    case Date.HOUR:
+      d.setHours(this.getHours() + value);
+      break;
+    case Date.DAY:
+      d.setDate(this.getDate() + value);
+      break;
+    case Date.MONTH:
+      var day = this.getDate();
+      if(day > 28){
+          day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
+      }
+      d.setDate(day);
+      d.setMonth(this.getMonth() + value);
+      break;
+    case Date.YEAR:
+      d.setFullYear(this.getFullYear() + value);
+      break;
+  }
+  return d;
+};
\ No newline at end of file
diff --git a/GitMonitor.js b/GitMonitor.js
new file mode 100644 (file)
index 0000000..5ab6e51
--- /dev/null
@@ -0,0 +1,379 @@
+
+var Gio      = imports.gi.Gio;
+var Gtk      = imports.gi.Gtk;
+var Notify   = imports.gi.Notify;
+var GLib     = imports.gi.GLib;
+
+var Spawn = imports.Spawn;
+var StatusIcon = imports.StatusIcon.StatusIcon;
+var Monitor = imports.Monitor.Monitor;
+
+
+
+var GitMonitor = new Monitor({
+    
+    /**
+     * @property {String} the "gitlive" directory, normally ~/gitlive
+     *  dset by OWNER... - we should do this as a CTOR.
+     *  
+     */
+    gitlive : false,
+    
+    
+    queue : [],
+    queueRunning : false,
+     
+     
+     
+    pause : function() {
+        this.paused = true;
+        this.queue = [];
+        imports.StatusIcon.StatusIcon.el.set_from_stock( Gtk.STOCK_MEDIA_PAUSE );
+    },
+    
+    resume : function() {
+        this.paused = false;
+        this.queue = [];
+        imports.StatusIcon.StatusIcon.el.set_from_stock( Gtk.STOCK_MEDIA_PLAY );
+        
+        
+    },
+    
+    
+    start: function() {
+        var _this = this;
+        this.lastAdd = new Date();
+        
+        this.top.forEach(this.monitor, this);
+         
+        GLib.timeout_add(GLib.PRIORITY_LOW, 500, function() {
+            //TIMEOUT", _this.queue.length , _this.queueRunning].join(', '));
+            if (!_this.queue.length || _this.queueRunning) {
+                return 1;
+            }
+            var last = Math.floor(((new Date()) - this.lastAdd) / 100);
+            if (last < 4) { // wait 1/2 a seconnd before running.
+                return 1;
+            }
+            _this.runQueue();
+            return 1;
+        },null,null);
+        
+        try { 
+            var notification = new Notify.Notification({
+                summary: "Git Live",
+                body : this.gitlive + "\nMonitoring " + this.monitors.length + " Directories",
+                timeout : 5
+            });
+    
+            notification.set_timeout(5);
+            notification.show();
+        } catch(e) {
+            print(e.toString());
+        }
+
+    },
+    
+    /**
+     * run the queue.
+     * - pulls the items off the queue 
+     *    (as commands run concurrently and new items may get added while it's running)
+     * - runs the queue items
+     * - pushes upstream.
+     * 
+     */
+    runQueue: function()
+    {
+        
+        if (this.paused) {
+            return;
+        }
+        this.queueRunning = true;
+        var cmds = [];
+        this.queue.forEach(function (q) {
+            cmds.push(q);
+        });
+        this.queue = []; // empty queue!
+        
+        var success = [];
+        var failure = [];
+        var repos = [];
+        var done = [];
+        
+        // first build a array of repo's to work with
+        var repo_list = {};
+        
+        // pull and group.
+        
+        //print(JSON.stringify(cmds));
+        
+        cmds.forEach(function(cmd) {
+            var gitpath = cmd.shift(); 
+            if (typeof(repo_list[gitpath]) == 'undefined') {
+                repo_list[gitpath] = new imports.Scm.Git.Repo.Repo( { repopath : gitpath });
+                repo_list[gitpath].cmds = [];
+                repo_list[gitpath].pull();
+            }
+            repo_list[gitpath].cmds.push(cmd);
+        });
+        
+        // build add, remove and commit message list..
+        
+         
+        for (var gitpath in repo_list) {
+            var repo = repo_list[gitpath];
+            var add_files = [];
+            var remove_files = [];
+            var messages = [];
+            repo.cmds.forEach(function(cmd) {
+                //print(JSON.stringify(cmd));
+                var name = cmd.shift();
+                var arg = cmd.shift();
+                
+                switch(name) {
+                    case 'add' :
+                        if (add_files.indexOf(arg) > -1) break;
+                        add_files.push(arg);
+                        break;
+                    
+                    case 'rm':
+                        remove_files.push(arg);
+                        break;
+                    
+                    case 'commit' :
+                        messages.push(arg.message);
+                        break;    
+                } 
+            });
+            //repo.debug = 1;
+            // these can fail... at present... as we wildcard stuff.
+            repo.add(add_files); 
+            repo.remove(remove_files);
+            
+            try { 
+                success.push(repo.commit({
+                    reason : messages.join("\n"),
+                    files : add_files  
+                }));
+                success.push(repo.push());
+
+            } catch(e) {
+                failure.push(e.message);
+                
+            }   
+        }
+        
+        // finally merge all the commit messages.
+         
+        try {
+            // catch notification failures.. so we can carry on..
+            if (success.length) {
+                print(success.join("\n"));
+                
+                var notification = new Notify.Notification({
+                    summary: "Git Live Commited",
+                    body : success.join("\n"),
+                    timeout : 5
+                    
+                });
+    
+                notification.set_timeout(5);
+                notification.show();   
+            }
+            
+            if (failure.length) {
+            
+                var notification = new Notify.Notification({
+                    summary: "Git Live ERROR!!",
+                    body : failure.join("\n"),
+                    timeout : 5
+                    
+                });
+    
+                notification.set_timeout(5); // show errros for longer
+                notification.show();   
+            }
+        } catch(e) {
+            print(e.toString());
+            
+        }
+        this.queueRunning = false;
+    },
+    
+    shouldIgnore: function(f)
+    {
+        
+        if (this.paused) {
+            return true;
+        }
+        if (f.name[0] == '.') {
+            // except!
+            if (f.name == '.htaccess') {
+                return false;
+            }
+            
+            return true;
+        }
+        if (f.name.match(/~$/)) {
+            return true;
+        }
+        // ignore anything in top level!!!!
+        if (!f.vpath.length) {
+            return true;
+        }
+        
+        return false;
+    },
+    
+    /**
+     * parsePath:
+     * Fill in gitlive, vpath and repo  
+     * 
+     */
+    parsePath: function(f)
+    {
+           
+        var vpath_ar = f.path.substring(this.gitlive.length +1).split('/');
+        
+        f.gitpath = this.gitlive + '/' + vpath_ar.shift();
+        f.vpath =  vpath_ar.join('/');
+        //f.repo = new imports.Scm.Git.Repo({ repopath: f.gitpath })
+        
+        
+    },
+    
+    just_created : {},
+      
+    onChanged : function(src) 
+    { 
+        return; // always ignore this..?
+        //this.parsePath(src);
+    },
+    
+    
+    
+    
+    /**
+     *  results in  git add  + git commit..
+     *
+     */
+    onChangesDoneHint : function(src) 
+    { 
+        this.parsePath(src);
+        if (this.shouldIgnore(src)) {
+            return;
+        }
+        
+       
+        var add_it = false;
+        if (typeof(this.just_created[src.path]) !='undefined') {
+            delete this.just_created[src.path];
+            this.lastAdd = new Date();
+            this.queue.push( 
+                [ src.gitpath,  'add', src.vpath ],
+                [ src.gitpath,  'commit',    { message: src.vpath} ] 
+                
+            );
+         
+            return;
+        }
+        this.lastAdd = new Date();
+        this.queue.push( 
+            [ src.gitpath,  'add', src.vpath ],
+            [ src.gitpath,  'commit',  {  message: src.vpath} ]
+
+            
+        );
+    },
+    onDeleted : function(src) 
+    { 
+        this.parsePath(src);
+        if (this.shouldIgnore(src)) {
+            return;
+        }
+        // should check if monitor needs removing..
+        // it should also check if it was a directory.. - so we dont have to commit all..
+        
+        this.lastAdd = new Date();
+        this.queue.push( 
+            [ src.gitpath, 'rm' , src.vpath ],
+            [ src.gitpath, 'commit', { all: true, message: src.vpath} ]
+            
+        );
+    
+        
+    },
+    onCreated : function(src) 
+    { 
+        this.parsePath(src);
+        if (this.shouldIgnore(src)) {
+            return;
+        }
+        
+        if (!GLib.file_test(src.path, GLib.FileTest.IS_DIR)) {
+            this.just_created[src.path] = true;
+            return; // we do not handle file create flags... - use done hint.
+        }
+        // director has bee created
+        this.monitor(src.path);
+        this.lastAdd = new Date();
+        this.queue.push( 
+            [ src.gitpath, 'add' , src.vpath,  { all: true } ],
+            [ src.gitpath, 'commit' , { all: true, message: src.vpath} ]
+            
+        );
+        
+        
+    },
+    onAttributeChanged : function(src) { 
+        this.parsePath(src);
+        if (this.shouldIgnore(src)) {
+            return;
+        }
+        this.lastAdd = new Date();
+        this.queue.push(
+                        
+            //[ src.gitpath, 'commit' ,  src.vpath, { message: src.vpath} ]
+            [ src.gitpath, 'add' ,  src.vpath ],
+             [ src.gitpath, 'commit' ,    {  message: "Attribute Changed :" + src.vpath} ]
+        );
+    
+    },
+    
+    onMoved : function(src,dest)
+    { 
+        this.parsePath(src);
+        this.parsePath(dest);
+        
+        if (src.gitpath != dest.gitpath) {
+            this.onDeleted(src);
+            this.onCreated(dest);
+            this.onChangedDoneHint(dest);
+            return;
+        }
+        // needs to handle move to/from unsupported types..
+        
+        if (this.shouldIgnore(src)) {
+            return;
+        }
+        if (this.shouldIgnore(dest)) {
+            return;
+        }
+        this.lastAdd = new Date();
+        this.queue.push( 
+           // [ src.gitpath, 'mv',  '-k', src.vpath, dest.vpath ],
+             [ src.gitpath, 'add',    dest.vpath ],
+             [ src.gitpath, 'rm',    src.vpath ],
+             
+            [ src.gitpath, 'commit' , 
+                { message:   'MOVED ' + src.vpath +' to ' + dest.vpath}
+            ]
+        );
+         
+    }
+          
+    
+});
\ No newline at end of file
diff --git a/Merger.bjs b/Merger.bjs
new file mode 100644 (file)
index 0000000..e42c2f7
--- /dev/null
@@ -0,0 +1,276 @@
+{
+    "id": "file-gtk-5",
+    "name": "Merger",
+    "parent": "",
+    "title": false,
+    "path": "/home/alan/gitlive/gitlive/Merger.bjs",
+    "items": [
+        {
+            "listeners": {
+                "destroy_event": "function (self, event) {\n     this.el.hide();\n                return false;\n}",
+                "response": "function (self, id) {\n  // hide\n     //if (id < 1) {\n        this.el.hide();\n        return;\n    //}\n    if (typeof(this.get('bug').getValue()) != 'object') {\n        print(\"ERROR\");\n        return;\n    }\n \n    this.el.hide();\n        \n    //var val = this.get('bug').getValue();\n     //   Seed.print(val);\n}"
+            },
+            "border_width": 3,
+            "default_height": 700,
+            "default_width": 800,
+            "id": "Merger",
+            "title": "Merger",
+            "xtype": "Dialog",
+            "|deletable": "true",
+            "|show": "function(c) {\n    \n    if (!this.el) {\n        this.init();\n    }\n    var _this = this;\n     \n      //this.el.set_title(\"Merger - ??? \");\n//   this.el.set_title(\"Merger - \" + this.repo.repopath);\n\n\n     Merger.loading = true; // stop change firing on combos.\n     /// load up branches\n     \n     this.get('/historyTreeStore').el.clear();\n     this.get('/changedFilesStore').el.clear();\n     this.get('/patchview').clear();\n    \n     \n     \n     this.get('/workingCombo').load(Merger.repo.branches);\n     \n     this.get('/releaseCombo').load(Merger.repo.branches);\n\n\n\n\n     Merger.loading = false;\n\n    this.el.show_all();\n    //this.get('/ok_button').el.set_sensitive(false);\n    \n    // block until we return.\n    var run_ret = this.el.run();\n    if (run_ret < 1 ) {\n        return  \"DONE\";\n    }\n    print(\"RUN RETURN : \" + run_ret);\n    return \"DONE\";\n    //print(JSON.stringify(this.get('bug').getValue()));\n   // return this.get('bug').getValue();\n    //this.success = c.success;\n}\n",
+            "|xns": "Gtk",
+            "items": [
+                {
+                    "xtype": "VBox",
+                    "|pack": " function(p,e) {\n        p.el.get_content_area().pack_start(e.el,true,true,0)\n    }\n",
+                    "|xns": "Gtk",
+                    "items": [
+                        {
+                            "pack": "pack_start,false,true",
+                            "xtype": "HBox",
+                            "|xns": "Gtk",
+                            "items": [
+                                {
+                                    "label": "Working Branch",
+                                    "xtype": "Label",
+                                    "|xns": "Gtk"
+                                },
+                                {
+                                    "listeners": {
+                                        "changed": "function (self) {\n   this.get('/historyTreeStore').loadTree();\n}"
+                                    },
+                                    "id": "workingCombo",
+                                    "xtype": "ComboBox",
+                                    "|init": "function() {\n    this.el = new Gtk.ComboBox.with_entry();\n    \n    \n    this.model  = new XObject(this.model);\n    this.model.init();\n    this.el.set_model(this.model.el);\n    this.el.set_entry_text_column (0);\n     XObject.prototype.init.call(this);\n    \n}\n",
+                                    "|load": "function(tr)\n{\n    //this.insert(citer,iter,0);\n    this.model.el.clear();\n    \n    var master = false;\n    var working = false;\n    \n    for(var i =0 ; i < tr.length; i++) {\n        if (!tr[i].name.length) {\n            continue;\n        }\n        var ret = {  };\n        this.model.el.append(ret);\n        //print(JSON.stringify(ret,null,4));\n        if (tr[i].name == 'master') {\n            master = i;\n        }\n        if (tr[i].name == 'working') {\n            working = i;\n        }          \n        this.model.el.set_value(ret.iter, 0, '' + tr[i].name );\n        this.model.el.set_value(ret.iter, 1, '' + tr[i].rev  );\n \n        \n    }     \n    if (master !== false) {\n        this.el.set_active(master);\n    }\n    if (working !== false) {\n        this.el.set_active(working);\n    }\n    \n}",
+                                    "|xns": "Gtk",
+                                    "items": [
+                                        {
+                                            "*prop": "model",
+                                            "xtype": "ListStore",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.set_column_types ( 3, [\n           GObject.TYPE_STRING, // file  \n          GObject.TYPE_STRING, // added\n          GObject.TYPE_STRING, // removed\n      ] );\n}\n",
+                                            "|xns": "Gtk"
+                                        }
+                                    ]
+                                },
+                                {
+                                    "label": "Release Branch",
+                                    "xtype": "Label",
+                                    "|xns": "Gtk"
+                                },
+                                {
+                                    "listeners": {
+                                        "changed": "function (self) {\n   this.get('/historyTreeStore').loadTree();\n}"
+                                    },
+                                    "id": "releaseCombo",
+                                    "xtype": "ComboBox",
+                                    "|init": "function() {\n    this.el = new Gtk.ComboBox.with_entry();\n    \n    \n    this.model  = new XObject(this.model);\n    this.model.init();\n    this.el.set_model(this.model.el);\n    this.el.set_entry_text_column (0);\n     XObject.prototype.init.call(this);\n    \n}\n",
+                                    "|load": "function(tr)\n{\n    //this.insert(citer,iter,0);\n    this.model.el.clear();\n    \n    var master = false;\n    var release = false;\n    \n    for(var i =0 ; i < tr.length; i++) {\n        var ret = {  };\n        if (!tr[i].name.length) {\n            continue;\n        }\n        \n        this.model.el.append(ret);\n        //print(JSON.stringify(ret,null,4));\n        if (tr[i].name == 'master') {\n            master = i;\n        }\n        if (tr[i].name == 'release') {\n            release = i;\n        }\n         \n        this.model.el.set_value(ret.iter, 0, '' + tr[i].name );\n        this.model.el.set_value(ret.iter, 1, '' + tr[i].rev  );\n \n        \n    }     \n    if (master !== false) {\n        this.el.set_active(master);\n    }\n    if (release !== false) {\n        this.el.set_active(release);\n    }\n    \n}",
+                                    "|xns": "Gtk",
+                                    "items": [
+                                        {
+                                            "*prop": "model",
+                                            "xtype": "ListStore",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.set_column_types ( 3, [\n           GObject.TYPE_STRING, // file  \n          GObject.TYPE_STRING, // added\n          GObject.TYPE_STRING, // removed\n      ] );\n}\n",
+                                            "|xns": "Gtk"
+                                        }
+                                    ]
+                                }
+                            ]
+                        },
+                        {
+                            "pack": "pack_end,true,true,0",
+                            "position": 400,
+                            "xtype": "VPaned",
+                            "|xns": "Gtk",
+                            "items": [
+                                {
+                                    "pack": "add",
+                                    "position": 200,
+                                    "xtype": "HPaned",
+                                    "|xns": "Gtk",
+                                    "items": [
+                                        {
+                                            "xtype": "ScrolledWindow",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n     this.el.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)\n}\n",
+                                            "|xns": "Gtk",
+                                            "items": [
+                                                {
+                                                    "listeners": {
+                                                        "cursor_changed": "function (self) {\n\n    if (this.el.get_selection().count_selected_rows() < 1) {\n        //nothing?\n        return;\n    }\n    var model = this.get('/historyTreeStore');\n    var ret = {};        \n     var s = this.el.get_selection();\n    s.get_selected(ret);\n    \n    var value = ''+ ret.model.get_value(ret.iter, 1).value.get_string();\n     print(\"OUT?\" + value);// id..\n    // load the list in the right grid..\n    var Repo = imports.Scm.Git.Repo.Repo;\n    \n    \n   \n    if (model.release === false) {\n        return;\n    }\n    model.rev = value;\n   \n    var files = Merger.repo.changedFiles('/',   'rev', model.release + '..' + value);\n    this.get('/changedFilesStore').load(files);\n    return true;\n\n}"
+                                                    },
+                                                    "pack": "add",
+                                                    "xtype": "TreeView",
+                                                    "|init": "function() {\n    XObject.prototype.init.call(this);\n        var description = new Pango.FontDescription.c_new();\n   description.set_size(8000);\n     this.el.modify_font(description);\n\n     this.selection = this.el.get_selection();\n      this.selection.set_mode( Gtk.SelectionMode.SINGLE);\n    var _this = this;\n    /*\n 780                                                                     \n 781                                                                         // is this really needed??\n 782                                                                         this.selection.signal['changed'].connect(function() {\n 783                                                                                 _this.get('/LeftTree.view').listeners.cursor_changed.apply(\n 784                                                                                     _this.get('/LeftTree.view'), [ _this.get('/LeftTree.view'), '']\n 785                                                                                 );\n 786                                                                         });\n 787                                                                         \n */\n }\n",
+                                                    "|xns": "Gtk",
+                                                    "items": [
+                                                        {
+                                                            "id": "historyTreeStore",
+                                                            "pack": "set_model",
+                                                            "release": false,
+                                                            "xtype": "TreeStore",
+                                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.set_column_types ( 3, [\n       GObject.TYPE_STRING, // title \n      GObject.TYPE_STRING, // rev \n  ] );\n}\n",
+                                                            "|load": "function(tr,iter)\n{\n    //this.insert(citer,iter,0);\n    if (!iter) {\n        this.el.clear();\n    }\n    \n    for(var i =0 ; i < tr.length; i++) {\n        var ret = {  };\n        if (iter) {\n            this.el.insert(ret ,iter,-1);\n        } else {\n            this.el.append(ret);\n        }\n        //print(JSON.stringify(ret,null,4));\n         \n          \n        this.el.set_value(ret.iter, 0, ''  +  tr[i].text );\n        this.el.set_value(ret.iter, 1, '' + tr[i].rev  );\n \n        if (tr[i].children && tr[i].children.length) {\n            this.load(tr[i].children, ret.iter);\n        }\n    }     \n}",
+                                                            "|loadTree": "function() {\n\n   this.working = false;\n   if (Merger.loading) {\n        return;\n   }\n   \n   \n   var wid = this.get('/workingCombo').el.get_active();\n   var rid = this.get('/releaseCombo').el.get_active();\n   if (wid < 0 || rid < 0 || rid == wid) {\n        return;\n   }\n   \n   var w = Merger.repo.branches[wid];\n   var r = Merger.repo.branches[rid];\n   \n\n\n    var rev = r.name + '..' + w.name;\n    this.release = r.name;\n    this.working = w.name;\n    \n    // this takes some time, lets. try and dialog it..\n\n    \n    \n    \n    var msg = new Gtk.MessageDialog( {\n        buttons : Gtk.ButtonsType.NONE,\n        text: \"Loading History\"\n        \n    });\n    \n    msg.set_transient_for(Merger.el);\n    msg.set_modal(true);\n    msg.show_all();\n\n    var hist = Merger.repo.dayTree('/', false, 'rev', rev);\n    msg.hide();\n    \n    this.load(hist);\n        \n       \n}\n",
+                                                            "|xns": "Gtk"
+                                                        },
+                                                        {
+                                                            "pack": "append_column",
+                                                            "title": "Changes",
+                                                            "xtype": "TreeViewColumn",
+                                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.add_attribute(this.items[0].el , 'markup', 0 );\n\n}\n",
+                                                            "|xns": "Gtk",
+                                                            "items": [
+                                                                {
+                                                                    "pack": "pack_start",
+                                                                    "xtype": "CellRendererText",
+                                                                    "|xns": "Gtk"
+                                                                }
+                                                            ]
+                                                        }
+                                                    ]
+                                                }
+                                            ]
+                                        },
+                                        {
+                                            "xtype": "ScrolledWindow",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n      this.el.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)\n}\n",
+                                            "|xns": "Gtk",
+                                            "items": [
+                                                {
+                                                    "listeners": {
+                                                        "cursor_changed": "function (self) {\n  // SEE SELECTION.CHANGED\n    var files = this.files();\n    this.get('/patchview').showDiff(files); \n    //var value = ''+ ret.model.get_value(ret.iter, 1).value.get_string();\n     //print(\"OUT?\" + value);// id..\n    // load the list in the right grid..\n     \n    return true;\n\n}"
+                                                    },
+                                                    "id": "changedFilesView",
+                                                    "pack": "add",
+                                                    "xtype": "TreeView",
+                                                    "|files": "function() {\n     if (this.el.get_selection().count_selected_rows() < 1) {\n        //nothing? - clea it?\n        return [];\n    }\n\n    var ret = {};         \n \n\n     var s = this.el.get_selection();\n     var files = [];\n      s.selected_foreach(function(model,p,iter) {\n    \n       files.push( model.get_value(iter, 0).value.get_string());\n     \n    });\n    return files;\n}\n",
+                                                    "|init": "function() {\n    XObject.prototype.init.call(this);\n        var description = new Pango.FontDescription.c_new();\n   description.set_size(8000);\n     this.el.modify_font(description);\n\n     this.selection = this.el.get_selection();\n      this.selection.set_mode( Gtk.SelectionMode.MULTIPLE);\n    var _this = this;\n  this.selection.signal['changed'].connect(function() {\n     _this.listeners.cursor_changed.apply(\n          _this, [ _this, '']\n       );\n             });\n  }\n",
+                                                    "|xns": "Gtk",
+                                                    "items": [
+                                                        {
+                                                            "id": "changedFilesStore",
+                                                            "pack": "set_model",
+                                                            "xtype": "ListStore",
+                                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.set_column_types ( 3, [\n       GObject.TYPE_STRING, // file  \n      GObject.TYPE_STRING, // added\n      GObject.TYPE_STRING, // removed\n  ] );\n}\n",
+                                                            "|load": "function(tr)\n{\n    //this.insert(citer,iter,0);\n    this.el.clear();\n    for(var i =0 ; i < tr.length; i++) {\n        var ret = {  };\n       \n        this.el.append(ret);\n        \n        //print(JSON.stringify(ret,null,4));\n         \n          \n        this.el.set_value(ret.iter, 0, ''  +  tr[i].filename );\n        this.el.set_value(ret.iter, 1, '' + tr[i].added  );\n        this.el.set_value(ret.iter, 2, '' + tr[i].removed  );\n \n        \n    }     \n}",
+                                                            "|xns": "Gtk"
+                                                        },
+                                                        {
+                                                            "resizable": true,
+                                                            "min_width": 200,
+                                                            "pack": "append_column",
+                                                            "title": "Filename",
+                                                            "xtype": "TreeViewColumn",
+                                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.add_attribute(this.items[0].el , 'markup', 0 );\n\n}\n",
+                                                            "|xns": "Gtk",
+                                                            "items": [
+                                                                {
+                                                                    "pack": "pack_start",
+                                                                    "xtype": "CellRendererText",
+                                                                    "|xns": "Gtk"
+                                                                }
+                                                            ]
+                                                        },
+                                                        {
+                                                            "min_width": 50,
+                                                            "pack": "append_column",
+                                                            "title": "Added",
+                                                            "xtype": "TreeViewColumn",
+                                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.add_attribute(this.items[0].el , 'markup', 1 );\n\n}\n",
+                                                            "|xns": "Gtk",
+                                                            "items": [
+                                                                {
+                                                                    "pack": "pack_start",
+                                                                    "xtype": "CellRendererText",
+                                                                    "|xns": "Gtk"
+                                                                }
+                                                            ]
+                                                        },
+                                                        {
+                                                            "min_width": 50,
+                                                            "pack": "append_column",
+                                                            "title": "Removed",
+                                                            "xtype": "TreeViewColumn",
+                                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.add_attribute(this.items[0].el , 'markup', 2 );\n\n}\n",
+                                                            "|xns": "Gtk",
+                                                            "items": [
+                                                                {
+                                                                    "pack": "pack_start",
+                                                                    "xtype": "CellRendererText",
+                                                                    "|xns": "Gtk"
+                                                                }
+                                                            ]
+                                                        }
+                                                    ]
+                                                },
+                                                {
+                                                    "|xns": "Gtk",
+                                                    "xtype": "TreeView",
+                                                    "pack": false,
+                                                    "items": [
+                                                        {
+                                                            "|xns": "Gtk",
+                                                            "xtype": "ListStore",
+                                                            "pack": false
+                                                        }
+                                                    ]
+                                                }
+                                            ]
+                                        }
+                                    ]
+                                },
+                                {
+                                    "xtype": "VBox",
+                                    "|xns": "Gtk",
+                                    "items": [
+                                        {
+                                            "pack": "pack_start,false,false,0",
+                                            "xtype": "HBox",
+                                            "|xns": "Gtk",
+                                            "items": [
+                                                {
+                                                    "listeners": {
+                                                        "clicked": "function (self) {\n    \n     \n     var model = this.get('/historyTreeStore');\n    \n    if (model.release === false) {\n        return;\n    }\n    \n \n    var files = this.get('/changedFilesView').files();\n    \n     if (!files.length) {\n        return; // error.!\n    }\n    var diff = Merger.repo.diff(files, model.release, model.rev);\n   \n   \n   print(\"history?\");\n   \n    \n    var history =  Merger.repo.history(files, 1, 'rev', model.rev);\n    \n    print(\"History\" + JSON.stringify(history, null,4));\n    \n    Commit = imports.Commit.Commit;\n\n    Commit.el.set_modal(true);\n    Commit.el.set_transient_for(Merger.el);\n\n    var ce = Commit.show({\n        repo : Merger.repo,\n        files : files,\n        release : model.release,\n        rev : model.rev,\n        author : history[0].changeby,\n        changed : history[0].changed_raw\n        \n    \n    });\n    if (ce === false ) {\n        return;\n    }\n    \n    \n    var diff = Merger.repo.diff(files, model.release, model.rev);\n    \n    \n    print(JSON.stringify(ce,null,4));\n    //.... commit!!!\n    \n    imports.GitMonitor.GitMonitor.pause();\n    try { \n        \n        Merger.repo.checkout(model.release);\n        \n        print(\"Call apply patch\");\n        \n        Merger.repo.applyPatch(diff);\n        \n        var author = Merger.repo.parseAuthor(ce.author);\n        \n        print(\"Add new files.\");\n        // add all the files..\n        Merger.repo.add(files);\n        \n        print(\"Commit changes.\");\n        Merger.repo.commit({\n            name    : author.name,\n            email   : author.email,\n            author  : ce.author,\n            changed : ce.changed,\n            reason  : ce.message,\n            files : files\n            \n        });\n        \n       \n    } catch (e) {\n     //message..\n          \n        var msg = new Gtk.MessageDialog({\n                message_type: Gtk.MessageType.ERROR, \n                buttons : Gtk.ButtonsType.OK, \n                text: e.message\n        });\n        msg.run();\n        msg.destroy();\n        Merger.repo.stash(); // revert change.. - so we can go back...\n    }\n    Merger.repo.checkout(model.working);\n    imports.GitMonitor.GitMonitor.resume();\n    \n    \n    \n    \n    \n    \n\n\n}"
+                                                    },
+                                                    "label": "Commit diff (no merge)",
+                                                    "xtype": "Button",
+                                                    "|xns": "Gtk"
+                                                }
+                                            ]
+                                        },
+                                        {
+                                            "pack": "pack_end,true,true,0",
+                                            "xtype": "ScrolledWindow",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n      this.el.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)\n}\n",
+                                            "|xns": "Gtk",
+                                            "items": [
+                                                {
+                                                    "id": "patchview",
+                                                    "pack": "add",
+                                                    "xtype": "WebView",
+                                                    "|clear": "function() {\n    \n    \n    \n     \n   // remove..\n    var s  = \"document.body.textContent='';\"\n        \n    this.el.execute_script(s);\n        \n        \n    \n    \n    \n}\n",
+                                                    "|showDiff": "function(files) {\n    this.clear();\n    \n    \n     var model = this.get('/historyTreeStore');\n    \n    if (model.release === false) {\n        return;\n    }\n    \n    var diff = Merger.repo.diff(files, model.release, model.rev);\n    \n   // remove..\n    var s  = \"var pre  = document.createElement('pre'); document.body.appendChild(pre);\";\n    s += \"pre.textContent =  \" +\n             JSON.stringify(Merger.repo.lastCmd + \"\\n\") + '+  ' + \n           JSON.stringify(diff) + \";\";\n    print(s);\n        \n    this.el.execute_script(s);\n        \n        \n    \n    \n    \n}\n",
+                                                    "|xns": "WebKit"
+                                                }
+                                            ]
+                                        }
+                                    ]
+                                }
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "id": "ok_button",
+                    "label": "Close",
+                    "pack": "add_action_widget,1",
+                    "xtype": "Button",
+                    "|xns": "Gtk"
+                }
+            ]
+        }
+    ],
+    "permname": "",
+    "modOrder": ""
+}
\ No newline at end of file
diff --git a/Merger.js b/Merger.js
new file mode 100644 (file)
index 0000000..d2f2154
--- /dev/null
+++ b/Merger.js
@@ -0,0 +1,757 @@
+Gtk = imports.gi.Gtk;
+Gdk = imports.gi.Gdk;
+Pango = imports.gi.Pango;
+GLib = imports.gi.GLib;
+Gio = imports.gi.Gio;
+GObject = imports.gi.GObject;
+GtkSource = imports.gi.GtkSource;
+WebKit = imports.gi.WebKit;
+Vte = imports.gi.Vte;
+console = imports.console;
+XObject = imports.XObject.XObject;
+Merger=new XObject({
+    xtype: Gtk.Dialog,
+    listeners : {
+        destroy_event : function (self, event) {
+             this.el.hide();
+                        return false;
+        },
+        response : function (self, id) {
+          // hide
+             //if (id < 1) {
+                this.el.hide();
+                return;
+            //}
+            if (typeof(this.get('bug').getValue()) != 'object') {
+                print("ERROR");
+                return;
+            }
+         
+            this.el.hide();
+                
+            //var val = this.get('bug').getValue();
+             //   Seed.print(val);
+        }
+    },
+    border_width : 3,
+    default_height : 700,
+    default_width : 800,
+    id : "Merger",
+    title : "Merger",
+    deletable : true,
+    show : function(c) {
+        
+        if (!this.el) {
+            this.init();
+        }
+        var _this = this;
+         
+          //this.el.set_title("Merger - ??? ");
+    //   this.el.set_title("Merger - " + this.repo.repopath);
+    
+    
+         Merger.loading = true; // stop change firing on combos.
+         /// load up branches
+         
+         this.get('/historyTreeStore').el.clear();
+         this.get('/changedFilesStore').el.clear();
+         this.get('/patchview').clear();
+        
+         
+         
+         this.get('/workingCombo').load(Merger.repo.branches);
+         
+         this.get('/releaseCombo').load(Merger.repo.branches);
+    
+    
+    
+    
+         Merger.loading = false;
+    
+        this.el.show_all();
+        //this.get('/ok_button').el.set_sensitive(false);
+        
+        // block until we return.
+        var run_ret = this.el.run();
+        if (run_ret < 1 ) {
+            return  "DONE";
+        }
+        print("RUN RETURN : " + run_ret);
+        return "DONE";
+        //print(JSON.stringify(this.get('bug').getValue()));
+       // return this.get('bug').getValue();
+        //this.success = c.success;
+    },
+    items : [
+        {
+            xtype: Gtk.VBox,
+            pack : function(p,e) {
+                    p.el.get_content_area().pack_start(e.el,true,true,0)
+                },
+            items : [
+                {
+                    xtype: Gtk.HBox,
+                    pack : "pack_start,false,true",
+                    items : [
+                        {
+                            xtype: Gtk.Label,
+                            label : "Working Branch"
+                        },
+                        {
+                            xtype: Gtk.ComboBox,
+                            listeners : {
+                                changed : function (self) {
+                                   this.get('/historyTreeStore').loadTree();
+                                }
+                            },
+                            id : "workingCombo",
+                            init : function() {
+                                this.el = new Gtk.ComboBox.with_entry();
+                                
+                                
+                                this.model  = new XObject(this.model);
+                                this.model.init();
+                                this.el.set_model(this.model.el);
+                                this.el.set_entry_text_column (0);
+                                 XObject.prototype.init.call(this);
+                                
+                            },
+                            load : function(tr)
+                            {
+                                //this.insert(citer,iter,0);
+                                this.model.el.clear();
+                                
+                                var master = false;
+                                var working = false;
+                                
+                                for(var i =0 ; i < tr.length; i++) {
+                                    if (!tr[i].name.length) {
+                                        continue;
+                                    }
+                                    var ret = {  };
+                                    this.model.el.append(ret);
+                                    //print(JSON.stringify(ret,null,4));
+                                    if (tr[i].name == 'master') {
+                                        master = i;
+                                    }
+                                    if (tr[i].name == 'working') {
+                                        working = i;
+                                    }          
+                                    this.model.el.set_value(ret.iter, 0, '' + tr[i].name );
+                                    this.model.el.set_value(ret.iter, 1, '' + tr[i].rev  );
+                             
+                                    
+                                }     
+                                if (master !== false) {
+                                    this.el.set_active(master);
+                                }
+                                if (working !== false) {
+                                    this.el.set_active(working);
+                                }
+                                
+                            },
+                            model : {
+                                xtype: Gtk.ListStore,
+                                init : function() {
+                                    XObject.prototype.init.call(this);
+                                    this.el.set_column_types ( 3, [
+                                           GObject.TYPE_STRING, // file  
+                                          GObject.TYPE_STRING, // added
+                                          GObject.TYPE_STRING, // removed
+                                      ] );
+                                }
+                            }
+                        },
+                        {
+                            xtype: Gtk.Label,
+                            label : "Release Branch"
+                        },
+                        {
+                            xtype: Gtk.ComboBox,
+                            listeners : {
+                                changed : function (self) {
+                                   this.get('/historyTreeStore').loadTree();
+                                }
+                            },
+                            id : "releaseCombo",
+                            init : function() {
+                                this.el = new Gtk.ComboBox.with_entry();
+                                
+                                
+                                this.model  = new XObject(this.model);
+                                this.model.init();
+                                this.el.set_model(this.model.el);
+                                this.el.set_entry_text_column (0);
+                                 XObject.prototype.init.call(this);
+                                
+                            },
+                            load : function(tr)
+                            {
+                                //this.insert(citer,iter,0);
+                                this.model.el.clear();
+                                
+                                var master = false;
+                                var release = false;
+                                
+                                for(var i =0 ; i < tr.length; i++) {
+                                    var ret = {  };
+                                    if (!tr[i].name.length) {
+                                        continue;
+                                    }
+                                    
+                                    this.model.el.append(ret);
+                                    //print(JSON.stringify(ret,null,4));
+                                    if (tr[i].name == 'master') {
+                                        master = i;
+                                    }
+                                    if (tr[i].name == 'release') {
+                                        release = i;
+                                    }
+                                     
+                                    this.model.el.set_value(ret.iter, 0, '' + tr[i].name );
+                                    this.model.el.set_value(ret.iter, 1, '' + tr[i].rev  );
+                             
+                                    
+                                }     
+                                if (master !== false) {
+                                    this.el.set_active(master);
+                                }
+                                if (release !== false) {
+                                    this.el.set_active(release);
+                                }
+                                
+                            },
+                            model : {
+                                xtype: Gtk.ListStore,
+                                init : function() {
+                                    XObject.prototype.init.call(this);
+                                    this.el.set_column_types ( 3, [
+                                           GObject.TYPE_STRING, // file  
+                                          GObject.TYPE_STRING, // added
+                                          GObject.TYPE_STRING, // removed
+                                      ] );
+                                }
+                            }
+                        }
+                    ]
+                },
+                {
+                    xtype: Gtk.VPaned,
+                    pack : "pack_end,true,true,0",
+                    position : 400,
+                    items : [
+                        {
+                            xtype: Gtk.HPaned,
+                            pack : "add",
+                            position : 200,
+                            items : [
+                                {
+                                    xtype: Gtk.ScrolledWindow,
+                                    init : function() {
+                                        XObject.prototype.init.call(this);
+                                         this.el.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
+                                    },
+                                    items : [
+                                        {
+                                            xtype: Gtk.TreeView,
+                                            listeners : {
+                                                cursor_changed : function (self) {
+                                                
+                                                    if (this.el.get_selection().count_selected_rows() < 1) {
+                                                        //nothing?
+                                                        return;
+                                                    }
+                                                    var model = this.get('/historyTreeStore');
+                                                    var ret = {};        
+                                                     var s = this.el.get_selection();
+                                                    s.get_selected(ret);
+                                                    
+                                                    var value = ''+ ret.model.get_value(ret.iter, 1).value.get_string();
+                                                     print("OUT?" + value);// id..
+                                                    // load the list in the right grid..
+                                                    var Repo = imports.Scm.Git.Repo.Repo;
+                                                    
+                                                    
+                                                   
+                                                    if (model.release === false) {
+                                                        return;
+                                                    }
+                                                    model.rev = value;
+                                                   
+                                                    var files = Merger.repo.changedFiles('/',   'rev', model.release + '..' + value);
+                                                    this.get('/changedFilesStore').load(files);
+                                                    return true;
+                                                
+                                                }
+                                            },
+                                            pack : "add",
+                                            init : function() {
+                                                XObject.prototype.init.call(this);
+                                                    var description = new Pango.FontDescription.c_new();
+                                               description.set_size(8000);
+                                                 this.el.modify_font(description);
+                                            
+                                                 this.selection = this.el.get_selection();
+                                                  this.selection.set_mode( Gtk.SelectionMode.SINGLE);
+                                                var _this = this;
+                                                /*
+                                             780                                                                     
+                                             781                                                                         // is this really needed??
+                                             782                                                                         this.selection.signal['changed'].connect(function() {
+                                             783                                                                                 _this.get('/LeftTree.view').listeners.cursor_changed.apply(
+                                             784                                                                                     _this.get('/LeftTree.view'), [ _this.get('/LeftTree.view'), '']
+                                             785                                                                                 );
+                                             786                                                                         });
+                                             787                                                                         
+                                             */
+                                             },
+                                            items : [
+                                                {
+                                                    xtype: Gtk.TreeStore,
+                                                    id : "historyTreeStore",
+                                                    pack : "set_model",
+                                                    release : false,
+                                                    init : function() {
+                                                        XObject.prototype.init.call(this);
+                                                        this.el.set_column_types ( 3, [
+                                                           GObject.TYPE_STRING, // title 
+                                                          GObject.TYPE_STRING, // rev 
+                                                      ] );
+                                                    },
+                                                    load : function(tr,iter)
+                                                    {
+                                                        //this.insert(citer,iter,0);
+                                                        if (!iter) {
+                                                            this.el.clear();
+                                                        }
+                                                        
+                                                        for(var i =0 ; i < tr.length; i++) {
+                                                            var ret = {  };
+                                                            if (iter) {
+                                                                this.el.insert(ret ,iter,-1);
+                                                            } else {
+                                                                this.el.append(ret);
+                                                            }
+                                                            //print(JSON.stringify(ret,null,4));
+                                                             
+                                                              
+                                                            this.el.set_value(ret.iter, 0, ''  +  tr[i].text );
+                                                            this.el.set_value(ret.iter, 1, '' + tr[i].rev  );
+                                                     
+                                                            if (tr[i].children && tr[i].children.length) {
+                                                                this.load(tr[i].children, ret.iter);
+                                                            }
+                                                        }     
+                                                    },
+                                                    loadTree : function() {
+                                                    
+                                                       this.working = false;
+                                                       if (Merger.loading) {
+                                                            return;
+                                                       }
+                                                       
+                                                       
+                                                       var wid = this.get('/workingCombo').el.get_active();
+                                                       var rid = this.get('/releaseCombo').el.get_active();
+                                                       if (wid < 0 || rid < 0 || rid == wid) {
+                                                            return;
+                                                       }
+                                                       
+                                                       var w = Merger.repo.branches[wid];
+                                                       var r = Merger.repo.branches[rid];
+                                                       
+                                                    
+                                                    
+                                                        var rev = r.name + '..' + w.name;
+                                                        this.release = r.name;
+                                                        this.working = w.name;
+                                                        
+                                                        // this takes some time, lets. try and dialog it..
+                                                    
+                                                        
+                                                        
+                                                        
+                                                        var msg = new Gtk.MessageDialog( {
+                                                            buttons : Gtk.ButtonsType.NONE,
+                                                            text: "Loading History"
+                                                            
+                                                        });
+                                                        
+                                                        msg.set_transient_for(Merger.el);
+                                                        msg.set_modal(true);
+                                                        msg.show_all();
+                                                    
+                                                        var hist = Merger.repo.dayTree('/', false, 'rev', rev);
+                                                        msg.hide();
+                                                        
+                                                        this.load(hist);
+                                                            
+                                                           
+                                                    }
+                                                },
+                                                {
+                                                    xtype: Gtk.TreeViewColumn,
+                                                    pack : "append_column",
+                                                    title : "Changes",
+                                                    init : function() {
+                                                        XObject.prototype.init.call(this);
+                                                        this.el.add_attribute(this.items[0].el , 'markup', 0 );
+                                                    
+                                                    },
+                                                    items : [
+                                                        {
+                                                            xtype: Gtk.CellRendererText,
+                                                            pack : "pack_start"
+                                                        }
+                                                    ]
+                                                }
+                                            ]
+                                        }
+                                    ]
+                                },
+                                {
+                                    xtype: Gtk.ScrolledWindow,
+                                    init : function() {
+                                        XObject.prototype.init.call(this);
+                                          this.el.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
+                                    },
+                                    items : [
+                                        {
+                                            xtype: Gtk.TreeView,
+                                            listeners : {
+                                                cursor_changed : function (self) {
+                                                  // SEE SELECTION.CHANGED
+                                                    var files = this.files();
+                                                    this.get('/patchview').showDiff(files); 
+                                                    //var value = ''+ ret.model.get_value(ret.iter, 1).value.get_string();
+                                                     //print("OUT?" + value);// id..
+                                                    // load the list in the right grid..
+                                                     
+                                                    return true;
+                                                
+                                                }
+                                            },
+                                            id : "changedFilesView",
+                                            pack : "add",
+                                            files : function() {
+                                                 if (this.el.get_selection().count_selected_rows() < 1) {
+                                                    //nothing? - clea it?
+                                                    return [];
+                                                }
+                                            
+                                                var ret = {};         
+                                             
+                                            
+                                                 var s = this.el.get_selection();
+                                                 var files = [];
+                                                  s.selected_foreach(function(model,p,iter) {
+                                                
+                                                   files.push( model.get_value(iter, 0).value.get_string());
+                                                 
+                                                });
+                                                return files;
+                                            },
+                                            init : function() {
+                                                XObject.prototype.init.call(this);
+                                                    var description = new Pango.FontDescription.c_new();
+                                               description.set_size(8000);
+                                                 this.el.modify_font(description);
+                                            
+                                                 this.selection = this.el.get_selection();
+                                                  this.selection.set_mode( Gtk.SelectionMode.MULTIPLE);
+                                                var _this = this;
+                                              this.selection.signal['changed'].connect(function() {
+                                                 _this.listeners.cursor_changed.apply(
+                                                      _this, [ _this, '']
+                                                   );
+                                                         });
+                                              },
+                                            items : [
+                                                {
+                                                    xtype: Gtk.ListStore,
+                                                    id : "changedFilesStore",
+                                                    pack : "set_model",
+                                                    init : function() {
+                                                        XObject.prototype.init.call(this);
+                                                        this.el.set_column_types ( 3, [
+                                                           GObject.TYPE_STRING, // file  
+                                                          GObject.TYPE_STRING, // added
+                                                          GObject.TYPE_STRING, // removed
+                                                      ] );
+                                                    },
+                                                    load : function(tr)
+                                                    {
+                                                        //this.insert(citer,iter,0);
+                                                        this.el.clear();
+                                                        for(var i =0 ; i < tr.length; i++) {
+                                                            var ret = {  };
+                                                           
+                                                            this.el.append(ret);
+                                                            
+                                                            //print(JSON.stringify(ret,null,4));
+                                                             
+                                                              
+                                                            this.el.set_value(ret.iter, 0, ''  +  tr[i].filename );
+                                                            this.el.set_value(ret.iter, 1, '' + tr[i].added  );
+                                                            this.el.set_value(ret.iter, 2, '' + tr[i].removed  );
+                                                     
+                                                            
+                                                        }     
+                                                    }
+                                                },
+                                                {
+                                                    xtype: Gtk.TreeViewColumn,
+                                                    resizable : true,
+                                                    min_width : 200,
+                                                    pack : "append_column",
+                                                    title : "Filename",
+                                                    init : function() {
+                                                        XObject.prototype.init.call(this);
+                                                        this.el.add_attribute(this.items[0].el , 'markup', 0 );
+                                                    
+                                                    },
+                                                    items : [
+                                                        {
+                                                            xtype: Gtk.CellRendererText,
+                                                            pack : "pack_start"
+                                                        }
+                                                    ]
+                                                },
+                                                {
+                                                    xtype: Gtk.TreeViewColumn,
+                                                    min_width : 50,
+                                                    pack : "append_column",
+                                                    title : "Added",
+                                                    init : function() {
+                                                        XObject.prototype.init.call(this);
+                                                        this.el.add_attribute(this.items[0].el , 'markup', 1 );
+                                                    
+                                                    },
+                                                    items : [
+                                                        {
+                                                            xtype: Gtk.CellRendererText,
+                                                            pack : "pack_start"
+                                                        }
+                                                    ]
+                                                },
+                                                {
+                                                    xtype: Gtk.TreeViewColumn,
+                                                    min_width : 50,
+                                                    pack : "append_column",
+                                                    title : "Removed",
+                                                    init : function() {
+                                                        XObject.prototype.init.call(this);
+                                                        this.el.add_attribute(this.items[0].el , 'markup', 2 );
+                                                    
+                                                    },
+                                                    items : [
+                                                        {
+                                                            xtype: Gtk.CellRendererText,
+                                                            pack : "pack_start"
+                                                        }
+                                                    ]
+                                                }
+                                            ]
+                                        },
+                                        {
+                                            xtype: Gtk.TreeView,
+                                            pack : false,
+                                            items : [
+                                                {
+                                                    xtype: Gtk.ListStore,
+                                                    pack : false
+                                                }
+                                            ]
+                                        }
+                                    ]
+                                }
+                            ]
+                        },
+                        {
+                            xtype: Gtk.VBox,
+                            items : [
+                                {
+                                    xtype: Gtk.HBox,
+                                    pack : "pack_start,false,false,0",
+                                    items : [
+                                        {
+                                            xtype: Gtk.Button,
+                                            listeners : {
+                                                clicked : function (self) {
+                                                    
+                                                     
+                                                     var model = this.get('/historyTreeStore');
+                                                    
+                                                    if (model.release === false) {
+                                                        return;
+                                                    }
+                                                    
+                                                 
+                                                    var files = this.get('/changedFilesView').files();
+                                                    
+                                                     if (!files.length) {
+                                                        return; // error.!
+                                                    }
+                                                    var diff = Merger.repo.diff(files, model.release, model.rev);
+                                                   
+                                                   
+                                                   print("history?");
+                                                   
+                                                    
+                                                    var history =  Merger.repo.history(files, 1, 'rev', model.rev);
+                                                    
+                                                    print("History" + JSON.stringify(history, null,4));
+                                                    
+                                                    Commit = imports.Commit.Commit;
+                                                
+                                                    Commit.el.set_modal(true);
+                                                    Commit.el.set_transient_for(Merger.el);
+                                                
+                                                    var ce = Commit.show({
+                                                        repo : Merger.repo,
+                                                        files : files,
+                                                        release : model.release,
+                                                        rev : model.rev,
+                                                        author : history[0].changeby,
+                                                        changed : history[0].changed_raw
+                                                        
+                                                    
+                                                    });
+                                                    if (ce === false ) {
+                                                        return;
+                                                    }
+                                                    
+                                                    
+                                                    var diff = Merger.repo.diff(files, model.release, model.rev);
+                                                    
+                                                    
+                                                    print(JSON.stringify(ce,null,4));
+                                                    //.... commit!!!
+                                                    
+                                                    imports.GitMonitor.GitMonitor.pause();
+                                                    try { 
+                                                        
+                                                        Merger.repo.checkout(model.release);
+                                                        
+                                                        print("Call apply patch");
+                                                        
+                                                        Merger.repo.applyPatch(diff);
+                                                        
+                                                        var author = Merger.repo.parseAuthor(ce.author);
+                                                        
+                                                        print("Add new files.");
+                                                        // add all the files..
+                                                        Merger.repo.add(files);
+                                                        
+                                                        print("Commit changes.");
+                                                        Merger.repo.commit({
+                                                            name    : author.name,
+                                                            email   : author.email,
+                                                            author  : ce.author,
+                                                            changed : ce.changed,
+                                                            reason  : ce.message,
+                                                            files : files
+                                                            
+                                                        });
+                                                        
+                                                       
+                                                    } catch (e) {
+                                                     //message..
+                                                          
+                                                        var msg = new Gtk.MessageDialog({
+                                                                message_type: Gtk.MessageType.ERROR, 
+                                                                buttons : Gtk.ButtonsType.OK, 
+                                                                text: e.message
+                                                        });
+                                                        msg.run();
+                                                        msg.destroy();
+                                                        Merger.repo.stash(); // revert change.. - so we can go back...
+                                                    }
+                                                    Merger.repo.checkout(model.working);
+                                                    imports.GitMonitor.GitMonitor.resume();
+                                                    
+                                                    
+                                                    
+                                                    
+                                                    
+                                                    
+                                                
+                                                
+                                                }
+                                            },
+                                            label : "Commit diff (no merge)"
+                                        }
+                                    ]
+                                },
+                                {
+                                    xtype: Gtk.ScrolledWindow,
+                                    pack : "pack_end,true,true,0",
+                                    init : function() {
+                                        XObject.prototype.init.call(this);
+                                          this.el.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
+                                    },
+                                    items : [
+                                        {
+                                            xtype: WebKit.WebView,
+                                            id : "patchview",
+                                            pack : "add",
+                                            clear : function() {
+                                                
+                                                
+                                                
+                                                 
+                                               // remove..
+                                                var s  = "document.body.textContent='';"
+                                                    
+                                                this.el.execute_script(s);
+                                                    
+                                                    
+                                                
+                                                
+                                                
+                                            },
+                                            showDiff : function(files) {
+                                                this.clear();
+                                                
+                                                
+                                                 var model = this.get('/historyTreeStore');
+                                                
+                                                if (model.release === false) {
+                                                    return;
+                                                }
+                                                
+                                                var diff = Merger.repo.diff(files, model.release, model.rev);
+                                                
+                                               // remove..
+                                                var s  = "var pre  = document.createElement('pre'); document.body.appendChild(pre);";
+                                                s += "pre.textContent =  " +
+                                                         JSON.stringify(Merger.repo.lastCmd + "\n") + '+  ' + 
+                                                       JSON.stringify(diff) + ";";
+                                                print(s);
+                                                    
+                                                this.el.execute_script(s);
+                                                    
+                                                    
+                                                
+                                                
+                                                
+                                            }
+                                        }
+                                    ]
+                                }
+                            ]
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            xtype: Gtk.Button,
+            id : "ok_button",
+            label : "Close",
+            pack : "add_action_widget,1"
+        }
+    ]
+});
+Merger.init();
+XObject.cache['/Merger'] = Merger;
diff --git a/Monitor.js b/Monitor.js
new file mode 100644 (file)
index 0000000..5d4ba1b
--- /dev/null
@@ -0,0 +1,229 @@
+//<Script type="text/javascript">
+var Gio      = imports.gi.Gio;
+var GLib      = imports.gi.GLib;
+
+
+/**
+ * Monitor class - handles monitor managment for a large tree...
+ * 
+ * usage : 
+ * x = new Monitor({
+     change : function () {
+         * ....
+         *}
+  }
+ * x.add('/somepath')
+ * x.stop() // stops all scanning.
+ * x.play(); // starts the scanning
+ * 
+ * 
+ * 
+ * 
+ */
+function Monitor(cfg){
+    for (var i in cfg) {
+        this[i] = cfg[i];
+    }
+    
+    
+    this.monitors = [];
+    
+    this.top = [];
+    
+}
+
+Monitor.prototype = {
+    
+    monitors : false, // Array of GioFileMonitors
+    top : false, // list of top level directories..
+    paused : false,
+    /**
+     * add a directory or file to monitor
+     */
+    add : function(add)
+    {
+        this.top.push(add);
+    },
+    /**
+     * start monitoring
+     */
+    start : function()
+    {
+        this.top.forEach(this.monitor, this);
+    },
+    /**
+     * stop / pause monitoring
+     * 
+     */
+    stop : function()
+    {
+        this.monitors.forEach(function(m) {
+            m.cancel();
+        })
+        this.monitors = [];
+    },
+    /**
+     * pause monitoring - without changing what's monitored 
+     */
+    pause : function()
+    {
+        this.paused = true;
+    },
+    /**
+     * resume monitoring - without changing what's monitored 
+     */
+    resume : function()
+    {
+        this.paused = false;
+    },
+    /**
+     * monitor a file or directory (privatish)
+     *
+     * initially called with ~/gitlive  null 0 (effectvely)
+     * 
+     * 
+     */
+    monitor : function(path, fn, depth)
+    {
+        var _this = this;
+        
+       // print("ADD: " + path)
+        
+        depth = typeof(depth) == 'number'  ? depth *1 : 0;
+        
+        
+        fn = fn || function (fm, f, of, event_type, uh) {
+            _this.onEvent(fm, f, of, event_type, uh);
+        }
+       
+        // if we are not at top level.. and there is a .git directory  (it's a submodule .. ignore) 
+        if (depth > 1 && GLib.file_test(path + '/.git' , GLib.FileTest.IS_DIR)) {
+            return;
+        }
+            
+       
+       
+        
+        var f = Gio.file_new_for_path(path);
+            //var cancel = new Gio.Cancellable ();
+        if (depth > 0) {     
+            var fm = f.monitor(2,null); //Gio.FileMonitorFlags.SEND_MOVED
+            fm.signal.changed.connect(fn);
+            this.monitors.push(fm);
+            // print("ADD path " + depth + ' ' + path);
+        }
+        // iterate children?
+        
+        if (GLib.file_test(path + '/.git' , GLib.FileTest.IS_DIR) && this.initRepo) {
+            
+            this.initRepo(path);
+        }
+        
+        
+        var file_enum = f.enumerate_children(
+            Gio.FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME + ','+ 
+            Gio.FILE_ATTRIBUTE_STANDARD_TYPE,
+            Gio.FileQueryInfoFlags.NONE,
+            null);
+        
+       
+        
+        while ((next_file = file_enum.next_file(null)) != null) {
+         
+            if (next_file.get_file_type() != Gio.FileType.DIRECTORY) {
+                continue;
+            }
+            if (next_file.get_display_name()[0] == '.') {
+                continue;
+            }
+            var sp = path+'/'+next_file.get_display_name();
+            // skip modules.
+           
+            
+            this.monitor(sp, fn, depth + 1)
+        }
+    
+        file_enum.close(null);
+    },
+    
+    
+    onEvent : function(fm, f, of, event_type, uh)
+    {
+        if (this.paused) {
+            return;
+        }
+        var src = {
+            name : f.get_basename(),
+            path : f.get_path(),
+            dir   : GLib.path_get_dirname(f.get_path())
+        };
+        var dest = of ? {
+            name : of.get_basename(),
+            path : of.get_path(),
+            dir   : GLib.path_get_dirname(of.get_path())
+        } : false;
+        
+        
+        for(var i in Gio.FileMonitorEvent) {
+            if (Gio.FileMonitorEvent[i] == event_type) {
+                event_name = i;
+            }
+        }
+        //print ("got event: " +event_name);
+        //print ("got src: " + src.toString());
+        //print ("got event: " + src.toString());
+        try {
+                
+            switch(event_type) {
+                case Gio.FileMonitorEvent.CHANGED:
+                    this.onChanged(src);
+                    return; // ingore thise?? -wait for changes_done_htin?
+                    
+                case Gio.FileMonitorEvent.CHANGES_DONE_HINT:
+                    this.onChangesDoneHint(src);
+                    return;
+                    
+                case Gio.FileMonitorEvent.DELETED:
+                    this.onDeleted(src);
+                    return;
+                    
+                case Gio.FileMonitorEvent.CREATED:
+                    this.onCreated(src);
+                    return;
+                
+                case Gio.FileMonitorEvent.ATTRIBUTE_CHANGED: // eg. chmod/chatt
+                    this.onAttributeChanged(src);
+                    return;
+                
+                case Gio.FileMonitorEvent.MOVED: // eg. chmod/chatt
+                    this.onMoved(src,dest);
+                    return; 
+                
+                // rest are mount related - not really relivant.. maybe add later..
+            } 
+        } catch(e) {
+            print(e);
+        }
+        
+    },
+    
+    /** override these to do stuff.. */
+    initRepo : function(src) { }, // called on startup at the top level repo dir.
+    onChanged : function(src) { },
+    onChangesDoneHint : function(src) { },
+    onDeleted : function(src) { },
+    onCreated : function(src) { },
+    onAttributeChanged : function(src) { },
+    onMoved : function(src) { }
+          
+    
+}
+
+
+
+
+
diff --git a/RemoteEdit.bjs b/RemoteEdit.bjs
new file mode 100644 (file)
index 0000000..2759ce9
--- /dev/null
@@ -0,0 +1,102 @@
+{
+    "id": "file-gtk-5",
+    "name": "RemoteEdit",
+    "parent": "",
+    "title": false,
+    "path": "/home/alan/gitlive/gitlive/RemoteEdit.bjs",
+    "items": [
+        {
+            "listeners": {
+                "destroy_event": "function (self, event) {\n     this.el.hide();\n                return false;\n}",
+                "response": "function (self, id) {\n  // hide\n     //if (id < 1) {\n        this.el.hide();\n        return;\n    //}\n    if (typeof(this.get('bug').getValue()) != 'object') {\n        print(\"ERROR\");\n        return;\n    }\n \n    this.el.hide();\n        \n    //var val = this.get('bug').getValue();\n     //   Seed.print(val);\n}"
+            },
+            " modal": true,
+            "border_width": 3,
+            "default_height": 150,
+            "default_width": 500,
+            "title": "Remotes",
+            "xtype": "Dialog",
+            "|deletable": true,
+            "|modal": true,
+            "|show": "function(c) {\n    \n    if (!this.el) {\n        this.init();\n    }\n    var _this = this;\n    //this.get('/remotesStore').load();\n    this.get('/remoteURL').el.get_child().set_text('');\n    this.get('/remoteName').el.set_text('');\n    \n    \n    this.el.show_all();\n    \n    var run_ret = this.el.run();\n    if (run_ret < 1 ) {\n        return false;\n    }\n    var ret=  {\n        url :  this.get('/remoteURL').el.get_child().get_text(),\n        name :  this.get('/remoteName').el.get_text()\n    };\n    \n    return ret;\n    \n    \n    \n}\n",
+            "|xns": "Gtk",
+            "items": [
+                {
+                    "xtype": "VBox",
+                    "|pack": " function(p,e) {\n        p.el.get_content_area().pack_start(e.el,true,true,10);\n    }\n",
+                    "|xns": "Gtk",
+                    "items": [
+                        {
+                            "pack": "pack_start,false,true,10",
+                            "xtype": "HBox",
+                            "|xns": "Gtk",
+                            "items": [
+                                {
+                                    "label": "URL :",
+                                    "pack": "pack_start,false,false,10",
+                                    "width_request": 50,
+                                    "xtype": "Label",
+                                    "|xns": "Gtk"
+                                },
+                                {
+                                    "listeners": {
+                                        "changed": "function (self) {\n   var val = this.el.get_child().get_text();\n   print(JSON.stringify(val));\n   if (!val.length) {\n       return;\n   }\n   \n   var name = this.get('/remoteName').el.get_text();\n   if (name.length) {\n       return;\n   }\n   // fill in name\n   var val = imports.Scm.Git.Repo.Repo.parseURL(val);\n   if ((typeof(val.host) != 'undefined') && val.host.length) {\n       var host = val.host;\n       // need to add github owner...\n        if (host.match(/github.com$/)) {\n          host += '.' + val.path.split('/').shift();\n        }\n   \n   \n        this.get('/remoteName').el.set_text(host);\n   }\n    \n   \n}"
+                                    },
+                                    "id": "remoteURL",
+                                    "xtype": "ComboBox",
+                                    "|init": "function() {\n    this.el = new Gtk.ComboBox.with_entry();\n    \n    \n    this.model  = new XObject(this.model);\n    this.model.init();\n    this.el.set_model(this.model.el);\n    this.el.set_entry_text_column (0);\n     XObject.prototype.init.call(this);\n    \n}\n",
+                                    "|load": "function(tr)\n{\n    //this.insert(citer,iter,0);\n    this.model.el.clear();\n    \n    var master = false;\n    var working = false;\n    \n    for(var i =0 ; i < tr.length; i++) {\n        var ret = {  };\n        this.model.el.append(ret);\n        //print(JSON.stringify(ret,null,4));\n        if (tr[i].name == 'master') {\n            master = i;\n        }\n        if (tr[i].name == 'working') {\n            working = i;\n        }          \n        this.model.el.set_value(ret.iter, 0, '' + tr[i].name );\n        this.model.el.set_value(ret.iter, 1, '' + tr[i].rev  );\n \n        \n    }     \n    if (master !== false) {\n        this.el.set_active(master);\n    }\n    if (working !== false) {\n        this.el.set_active(working);\n    }\n    \n}",
+                                    "|xns": "Gtk",
+                                    "items": [
+                                        {
+                                            "*prop": "model",
+                                            "xtype": "ListStore",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.set_column_types ( 3, [\n           GObject.TYPE_STRING, // file  \n          GObject.TYPE_STRING, // added\n          GObject.TYPE_STRING, // removed\n      ] );\n}\n",
+                                            "|xns": "Gtk"
+                                        }
+                                    ]
+                                }
+                            ]
+                        },
+                        {
+                            "pack": "pack_start,false,true,10",
+                            "xtype": "HBox",
+                            "|xns": "Gtk",
+                            "items": [
+                                {
+                                    "label": "Name : ",
+                                    "pack": "pack_start,false,false,10",
+                                    "width_request": 50,
+                                    "xalign": 1,
+                                    "xtype": "Label",
+                                    "|xns": "Gtk"
+                                },
+                                {
+                                    "id": "remoteName",
+                                    "xtype": "Entry",
+                                    "|xns": "Gtk"
+                                }
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "label": "Cancel",
+                    "pack": "add_action_widget,0",
+                    "xtype": "Button",
+                    "|xns": "Gtk",
+                    "listeners": {}
+                },
+                {
+                    "id": "ok_button",
+                    "label": "Add",
+                    "pack": "add_action_widget,1",
+                    "xtype": "Button",
+                    "|xns": "Gtk"
+                }
+            ]
+        }
+    ],
+    "permname": "",
+    "modOrder": "0"
+}
\ No newline at end of file
diff --git a/RemoteEdit.js b/RemoteEdit.js
new file mode 100644 (file)
index 0000000..5ab0874
--- /dev/null
@@ -0,0 +1,207 @@
+Gtk = imports.gi.Gtk;
+Gdk = imports.gi.Gdk;
+Pango = imports.gi.Pango;
+GLib = imports.gi.GLib;
+Gio = imports.gi.Gio;
+GObject = imports.gi.GObject;
+GtkSource = imports.gi.GtkSource;
+WebKit = imports.gi.WebKit;
+Vte = imports.gi.Vte;
+console = imports.console;
+XObject = imports.XObject.XObject;
+RemoteEdit=new XObject({
+    xtype: Gtk.Dialog,
+    listeners : {
+        destroy_event : function (self, event) {
+             this.el.hide();
+                        return false;
+        },
+        response : function (self, id) {
+          // hide
+             //if (id < 1) {
+                this.el.hide();
+                return;
+            //}
+            if (typeof(this.get('bug').getValue()) != 'object') {
+                print("ERROR");
+                return;
+            }
+         
+            this.el.hide();
+                
+            //var val = this.get('bug').getValue();
+             //   Seed.print(val);
+        }
+    },
+    ' modal' : true,
+    border_width : 3,
+    default_height : 150,
+    default_width : 500,
+    title : "Remotes",
+    deletable : true,
+    modal : true,
+    show : function(c) {
+        
+        if (!this.el) {
+            this.init();
+        }
+        var _this = this;
+        //this.get('/remotesStore').load();
+        this.get('/remoteURL').el.get_child().set_text('');
+        this.get('/remoteName').el.set_text('');
+        
+        
+        this.el.show_all();
+        
+        var run_ret = this.el.run();
+        if (run_ret < 1 ) {
+            return false;
+        }
+        var ret=  {
+            url :  this.get('/remoteURL').el.get_child().get_text(),
+            name :  this.get('/remoteName').el.get_text()
+        };
+        
+        return ret;
+        
+        
+        
+    },
+    items : [
+        {
+            xtype: Gtk.VBox,
+            pack : function(p,e) {
+                    p.el.get_content_area().pack_start(e.el,true,true,10);
+                },
+            items : [
+                {
+                    xtype: Gtk.HBox,
+                    pack : "pack_start,false,true,10",
+                    items : [
+                        {
+                            xtype: Gtk.Label,
+                            label : "URL :",
+                            pack : "pack_start,false,false,10",
+                            width_request : 50
+                        },
+                        {
+                            xtype: Gtk.ComboBox,
+                            listeners : {
+                                changed : function (self) {
+                                   var val = this.el.get_child().get_text();
+                                   print(JSON.stringify(val));
+                                   if (!val.length) {
+                                       return;
+                                   }
+                                   
+                                   var name = this.get('/remoteName').el.get_text();
+                                   if (name.length) {
+                                       return;
+                                   }
+                                   // fill in name
+                                   var val = imports.Scm.Git.Repo.Repo.parseURL(val);
+                                   if ((typeof(val.host) != 'undefined') && val.host.length) {
+                                       var host = val.host;
+                                       // need to add github owner...
+                                        if (host.match(/github.com$/)) {
+                                          host += '.' + val.path.split('/').shift();
+                                        }
+                                   
+                                   
+                                        this.get('/remoteName').el.set_text(host);
+                                   }
+                                    
+                                   
+                                }
+                            },
+                            id : "remoteURL",
+                            init : function() {
+                                this.el = new Gtk.ComboBox.with_entry();
+                                
+                                
+                                this.model  = new XObject(this.model);
+                                this.model.init();
+                                this.el.set_model(this.model.el);
+                                this.el.set_entry_text_column (0);
+                                 XObject.prototype.init.call(this);
+                                
+                            },
+                            load : function(tr)
+                            {
+                                //this.insert(citer,iter,0);
+                                this.model.el.clear();
+                                
+                                var master = false;
+                                var working = false;
+                                
+                                for(var i =0 ; i < tr.length; i++) {
+                                    var ret = {  };
+                                    this.model.el.append(ret);
+                                    //print(JSON.stringify(ret,null,4));
+                                    if (tr[i].name == 'master') {
+                                        master = i;
+                                    }
+                                    if (tr[i].name == 'working') {
+                                        working = i;
+                                    }          
+                                    this.model.el.set_value(ret.iter, 0, '' + tr[i].name );
+                                    this.model.el.set_value(ret.iter, 1, '' + tr[i].rev  );
+                             
+                                    
+                                }     
+                                if (master !== false) {
+                                    this.el.set_active(master);
+                                }
+                                if (working !== false) {
+                                    this.el.set_active(working);
+                                }
+                                
+                            },
+                            model : {
+                                xtype: Gtk.ListStore,
+                                init : function() {
+                                    XObject.prototype.init.call(this);
+                                    this.el.set_column_types ( 3, [
+                                           GObject.TYPE_STRING, // file  
+                                          GObject.TYPE_STRING, // added
+                                          GObject.TYPE_STRING, // removed
+                                      ] );
+                                }
+                            }
+                        }
+                    ]
+                },
+                {
+                    xtype: Gtk.HBox,
+                    pack : "pack_start,false,true,10",
+                    items : [
+                        {
+                            xtype: Gtk.Label,
+                            label : "Name : ",
+                            pack : "pack_start,false,false,10",
+                            width_request : 50,
+                            xalign : 1
+                        },
+                        {
+                            xtype: Gtk.Entry,
+                            id : "remoteName"
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            xtype: Gtk.Button,
+            label : "Cancel",
+            pack : "add_action_widget,0"
+        },
+        {
+            xtype: Gtk.Button,
+            id : "ok_button",
+            label : "Add",
+            pack : "add_action_widget,1"
+        }
+    ]
+});
+RemoteEdit.init();
+XObject.cache['/RemoteEdit'] = RemoteEdit;
diff --git a/Remotes.bjs b/Remotes.bjs
new file mode 100644 (file)
index 0000000..0d195f4
--- /dev/null
@@ -0,0 +1,152 @@
+{
+    "id": "file-gtk-4",
+    "name": "Remotes",
+    "parent": "",
+    "title": false,
+    "path": "/home/alan/gitlive/gitlive/Remotes.bjs",
+    "items": [
+        {
+            "listeners": {
+                "destroy_event": "function (self, event) {\n     this.el.hide();\n                return false;\n}",
+                "response": "function (self, id) {\n  // hide\n     //if (id < 1) {\n        this.el.hide();\n        return;\n    //}\n    if (typeof(this.get('bug').getValue()) != 'object') {\n        print(\"ERROR\");\n        return;\n    }\n \n    this.el.hide();\n        \n    //var val = this.get('bug').getValue();\n     //   Seed.print(val);\n}"
+            },
+            " modal": true,
+            "border_width": 3,
+            "default_height": 300,
+            "default_width": 500,
+            "title": "Remotes",
+            "xtype": "Dialog",
+            "|deletable": true,
+            "|modal": true,
+            "|show": "function(c) {\n    \n    if (!this.el) {\n        this.init();\n    }\n    var _this = this;\n    this.get('/remotesStore').load();\n    this.el.show_all();\n    \n    var run_ret = this.el.run();\n    if (run_ret < 1 ) {\n        return  \"DONE\";\n    }\n    print(\"RUN RETURN : \" + run_ret);\n    return \"DONE\";\n    \n}\n",
+            "|xns": "Gtk",
+            "items": [
+                {
+                    "xtype": "VBox",
+                    "|pack": " function(p,e) {\n        p.el.get_content_area().pack_start(e.el,true,true,0)\n    }\n",
+                    "|xns": "Gtk",
+                    "items": [
+                        {
+                            "pack": "pack_start,false,true",
+                            "xtype": "HBox",
+                            "|xns": "Gtk",
+                            "items": [
+                                {
+                                    "listeners": {
+                                        "clicked": "function (self) {\n\n        \n    var RemoteEdit=    imports.RemoteEdit.RemoteEdit\n     RemoteEdit.repo = Remotes.repo;\n    RemoteEdit.el.set_transient_for(Remotes.el);\n\n    var res =  RemoteEdit.show();\n    \n    if (res != false) {\n        Remotes.repo.remotes(res);\n    }\n    \n    this.get('/remotesStore').load();\n\n    \n}"
+                                    },
+                                    "label": "Add",
+                                    "pack": "add",
+                                    "xtype": "Button",
+                                    "|xns": "Gtk"
+                                }
+                            ]
+                        },
+                        {
+                            "xtype": "ScrolledWindow",
+                            "|init": "function() {\n    XObject.prototype.init.call(this);\n      this.el.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)\n}\n",
+                            "|xns": "Gtk",
+                            "items": [
+                                {
+                                    "listeners": {
+                                        "cursor_changed": "function (self)\n{\n\n   return;\n  // SEE SELECTION.CHANGED\n    if (this.el.get_selection().count_selected_rows() < 1) {\n        //nothing? - clea it?\n        return;\n    }\n        var ret = {};         \n    var model = this.get('/changedFilesStore');\n\n     var s = this.el.get_selection();\n     var files = [];\n    s.selected_foreach(function(model,p,iter) {\n    \n       files.push( model.get_value(iter, 0).value.get_string());\n     \n    });\n    this.get('/patchview').showDiff(files); \n    //var value = ''+ ret.model.get_value(ret.iter, 1).value.get_string();\n     //print(\"OUT?\" + value);// id..\n    // load the list in the right grid..\n     \n    return true;\n\n}"
+                                    },
+                                    "id": "remotesView",
+                                    "pack": "add",
+                                    "xtype": "TreeView",
+                                    "|init": "function() {\n    XObject.prototype.init.call(this);\n        var description = new Pango.FontDescription.c_new();\n   description.set_size(8000);\n     this.el.modify_font(description);\n\n     this.selection = this.el.get_selection();\n      this.selection.set_mode( Gtk.SelectionMode.MULTIPLE);\n    var _this = this;\n  this.selection.signal['changed'].connect(function() {\n     _this.listeners.cursor_changed.apply(\n          _this, [ _this, '']\n       );\n             });\n  }\n",
+                                    "|xns": "Gtk",
+                                    "items": [
+                                        {
+                                            "id": "remotesStore",
+                                            "pack": "set_model",
+                                            "xtype": "ListStore",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.set_column_types ( 3, [\n       GObject.TYPE_STRING, // file  \n      GObject.TYPE_STRING, // added\n      GObject.TYPE_STRING, // removed\n  ] );\n}\n",
+                                            "|load": "function(tr)\n{\n    //this.insert(citer,iter,0);\n    this.el.clear();\n    \n    var tr = Remotes.repo.remotes();\n    \n    \n    for(var i =0 ; i < tr.length; i++) {\n        var ret = {  };\n       \n        this.el.append(ret);\n        \n        //print(JSON.stringify(ret,null,4));\n         \n          \n        this.el.set_value(ret.iter, 0, ''  +  tr[i].name );\n        this.el.set_value(ret.iter, 1, '' + tr[i].url );\n       this.el.set_value(ret.iter, 2, '' + tr[i].type );\n \n        \n    }     \n}",
+                                            "|xns": "Gtk"
+                                        },
+                                        {
+                                            "min_width": 70,
+                                            "pack": "append_column",
+                                            "resizable": true,
+                                            "title": "Name",
+                                            "xtype": "TreeViewColumn",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.add_attribute(this.items[0].el , 'markup', 0 );\n\n}\n",
+                                            "|xns": "Gtk",
+                                            "items": [
+                                                {
+                                                    "pack": "pack_start",
+                                                    "xtype": "CellRendererText",
+                                                    "|xns": "Gtk"
+                                                }
+                                            ]
+                                        },
+                                        {
+                                            "min_width": 70,
+                                            "pack": "append_column",
+                                            "resizable": true,
+                                            "title": "Type",
+                                            "xtype": "TreeViewColumn",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.add_attribute(this.items[0].el , 'markup', 2 );\n\n}\n",
+                                            "|xns": "Gtk",
+                                            "items": [
+                                                {
+                                                    "pack": "pack_start",
+                                                    "xtype": "CellRendererText",
+                                                    "|xns": "Gtk"
+                                                }
+                                            ]
+                                        },
+                                        {
+                                            "min_width": 200,
+                                            "pack": "append_column",
+                                            "title": "URL",
+                                            "xtype": "TreeViewColumn",
+                                            "|init": "function() {\n    XObject.prototype.init.call(this);\n    this.el.add_attribute(this.items[0].el , 'markup', 1 );\n\n}\n",
+                                            "|xns": "Gtk",
+                                            "items": [
+                                                {
+                                                    "pack": "pack_start",
+                                                    "xtype": "CellRendererText",
+                                                    "|xns": "Gtk"
+                                                }
+                                            ]
+                                        }
+                                    ]
+                                },
+                                {
+                                    "|xns": "Gtk",
+                                    "xtype": "TreeView",
+                                    "pack": false,
+                                    "items": [
+                                        {
+                                            "|xns": "Gtk",
+                                            "xtype": "ListStore",
+                                            "pack": false
+                                        }
+                                    ]
+                                }
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "label": "Cancel",
+                    "pack": "add_action_widget,0",
+                    "xtype": "Button",
+                    "|xns": "Gtk",
+                    "listeners": {}
+                },
+                {
+                    "id": "ok_button",
+                    "label": "OK",
+                    "pack": "add_action_widget,1",
+                    "xtype": "Button",
+                    "|xns": "Gtk"
+                }
+            ]
+        }
+    ],
+    "permname": "",
+    "modOrder": "0"
+}
\ No newline at end of file
diff --git a/Remotes.js b/Remotes.js
new file mode 100644 (file)
index 0000000..f36424f
--- /dev/null
@@ -0,0 +1,272 @@
+Gtk = imports.gi.Gtk;
+Gdk = imports.gi.Gdk;
+Pango = imports.gi.Pango;
+GLib = imports.gi.GLib;
+Gio = imports.gi.Gio;
+GObject = imports.gi.GObject;
+GtkSource = imports.gi.GtkSource;
+WebKit = imports.gi.WebKit;
+Vte = imports.gi.Vte;
+console = imports.console;
+XObject = imports.XObject.XObject;
+Remotes=new XObject({
+    xtype: Gtk.Dialog,
+    listeners : {
+        destroy_event : function (self, event) {
+             this.el.hide();
+                        return false;
+        },
+        response : function (self, id) {
+          // hide
+             //if (id < 1) {
+                this.el.hide();
+                return;
+            //}
+            if (typeof(this.get('bug').getValue()) != 'object') {
+                print("ERROR");
+                return;
+            }
+         
+            this.el.hide();
+                
+            //var val = this.get('bug').getValue();
+             //   Seed.print(val);
+        }
+    },
+    ' modal' : true,
+    border_width : 3,
+    default_height : 300,
+    default_width : 500,
+    title : "Remotes",
+    deletable : true,
+    modal : true,
+    show : function(c) {
+        
+        if (!this.el) {
+            this.init();
+        }
+        var _this = this;
+        this.get('/remotesStore').load();
+        this.el.show_all();
+        
+        var run_ret = this.el.run();
+        if (run_ret < 1 ) {
+            return  "DONE";
+        }
+        print("RUN RETURN : " + run_ret);
+        return "DONE";
+        
+    },
+    items : [
+        {
+            xtype: Gtk.VBox,
+            pack : function(p,e) {
+                    p.el.get_content_area().pack_start(e.el,true,true,0)
+                },
+            items : [
+                {
+                    xtype: Gtk.HBox,
+                    pack : "pack_start,false,true",
+                    items : [
+                        {
+                            xtype: Gtk.Button,
+                            listeners : {
+                                clicked : function (self) {
+                                
+                                        
+                                    var RemoteEdit=    imports.RemoteEdit.RemoteEdit
+                                     RemoteEdit.repo = Remotes.repo;
+                                    RemoteEdit.el.set_transient_for(Remotes.el);
+                                
+                                    var res =  RemoteEdit.show();
+                                    
+                                    if (res != false) {
+                                        Remotes.repo.remotes(res);
+                                    }
+                                    
+                                    this.get('/remotesStore').load();
+                                
+                                    
+                                }
+                            },
+                            label : "Add",
+                            pack : "add"
+                        }
+                    ]
+                },
+                {
+                    xtype: Gtk.ScrolledWindow,
+                    init : function() {
+                        XObject.prototype.init.call(this);
+                          this.el.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
+                    },
+                    items : [
+                        {
+                            xtype: Gtk.TreeView,
+                            listeners : {
+                                cursor_changed : function (self)
+                                {
+                                
+                                   return;
+                                  // SEE SELECTION.CHANGED
+                                    if (this.el.get_selection().count_selected_rows() < 1) {
+                                        //nothing? - clea it?
+                                        return;
+                                    }
+                                        var ret = {};         
+                                    var model = this.get('/changedFilesStore');
+                                
+                                     var s = this.el.get_selection();
+                                     var files = [];
+                                    s.selected_foreach(function(model,p,iter) {
+                                    
+                                       files.push( model.get_value(iter, 0).value.get_string());
+                                     
+                                    });
+                                    this.get('/patchview').showDiff(files); 
+                                    //var value = ''+ ret.model.get_value(ret.iter, 1).value.get_string();
+                                     //print("OUT?" + value);// id..
+                                    // load the list in the right grid..
+                                     
+                                    return true;
+                                
+                                }
+                            },
+                            id : "remotesView",
+                            pack : "add",
+                            init : function() {
+                                XObject.prototype.init.call(this);
+                                    var description = new Pango.FontDescription.c_new();
+                               description.set_size(8000);
+                                 this.el.modify_font(description);
+                            
+                                 this.selection = this.el.get_selection();
+                                  this.selection.set_mode( Gtk.SelectionMode.MULTIPLE);
+                                var _this = this;
+                              this.selection.signal['changed'].connect(function() {
+                                 _this.listeners.cursor_changed.apply(
+                                      _this, [ _this, '']
+                                   );
+                                         });
+                              },
+                            items : [
+                                {
+                                    xtype: Gtk.ListStore,
+                                    id : "remotesStore",
+                                    pack : "set_model",
+                                    init : function() {
+                                        XObject.prototype.init.call(this);
+                                        this.el.set_column_types ( 3, [
+                                           GObject.TYPE_STRING, // file  
+                                          GObject.TYPE_STRING, // added
+                                          GObject.TYPE_STRING, // removed
+                                      ] );
+                                    },
+                                    load : function(tr)
+                                    {
+                                        //this.insert(citer,iter,0);
+                                        this.el.clear();
+                                        
+                                        var tr = Remotes.repo.remotes();
+                                        
+                                        
+                                        for(var i =0 ; i < tr.length; i++) {
+                                            var ret = {  };
+                                           
+                                            this.el.append(ret);
+                                            
+                                            //print(JSON.stringify(ret,null,4));
+                                             
+                                              
+                                            this.el.set_value(ret.iter, 0, ''  +  tr[i].name );
+                                            this.el.set_value(ret.iter, 1, '' + tr[i].url );
+                                           this.el.set_value(ret.iter, 2, '' + tr[i].type );
+                                     
+                                            
+                                        }     
+                                    }
+                                },
+                                {
+                                    xtype: Gtk.TreeViewColumn,
+                                    min_width : 70,
+                                    pack : "append_column",
+                                    resizable : true,
+                                    title : "Name",
+                                    init : function() {
+                                        XObject.prototype.init.call(this);
+                                        this.el.add_attribute(this.items[0].el , 'markup', 0 );
+                                    
+                                    },
+                                    items : [
+                                        {
+                                            xtype: Gtk.CellRendererText,
+                                            pack : "pack_start"
+                                        }
+                                    ]
+                                },
+                                {
+                                    xtype: Gtk.TreeViewColumn,
+                                    min_width : 70,
+                                    pack : "append_column",
+                                    resizable : true,
+                                    title : "Type",
+                                    init : function() {
+                                        XObject.prototype.init.call(this);
+                                        this.el.add_attribute(this.items[0].el , 'markup', 2 );
+                                    
+                                    },
+                                    items : [
+                                        {
+                                            xtype: Gtk.CellRendererText,
+                                            pack : "pack_start"
+                                        }
+                                    ]
+                                },
+                                {
+                                    xtype: Gtk.TreeViewColumn,
+                                    min_width : 200,
+                                    pack : "append_column",
+                                    title : "URL",
+                                    init : function() {
+                                        XObject.prototype.init.call(this);
+                                        this.el.add_attribute(this.items[0].el , 'markup', 1 );
+                                    
+                                    },
+                                    items : [
+                                        {
+                                            xtype: Gtk.CellRendererText,
+                                            pack : "pack_start"
+                                        }
+                                    ]
+                                }
+                            ]
+                        },
+                        {
+                            xtype: Gtk.TreeView,
+                            pack : false,
+                            items : [
+                                {
+                                    xtype: Gtk.ListStore,
+                                    pack : false
+                                }
+                            ]
+                        }
+                    ]
+                }
+            ]
+        },
+        {
+            xtype: Gtk.Button,
+            label : "Cancel",
+            pack : "add_action_widget,0"
+        },
+        {
+            xtype: Gtk.Button,
+            id : "ok_button",
+            label : "OK",
+            pack : "add_action_widget,1"
+        }
+    ]
+});
+Remotes.init();
+XObject.cache['/Remotes'] = Remotes;
diff --git a/Repo.js b/Repo.js
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Spawn.js b/Spawn.js
new file mode 100644 (file)
index 0000000..6a33511
--- /dev/null
+++ b/Spawn.js
@@ -0,0 +1,425 @@
+///<script type="text/javascript">
+
+var Gio      = imports.gi.Gio;
+var GLib      = imports.gi.GLib;
+
+
+/**
+* @namespace Spawn
+* 
+* Library to wrap GLib.spawn_async_with_pipes
+* 
+* usage:
+* 
+* Spawn = import.Spawn;
+* 
+* simple version..
+* var output = Spawn.run({
+*   cwd : '/home',
+*   args : [ 'ls', '-l' ],
+*   env : [], // optional
+*   listeners : {
+        output : function (line) { Seed.print(line); },
+*       stderr :  function (line) {Seed.print("ERROR" + line);  },
+*       input : function() { return 'xxx' },
+*   }
+*  });
+*
+*
+*
+
+*
+*
+*  CRITICAL - needs this change to gir in GLib-2.0.gir g_spawn_async_with_pipes
+*
+    <parameter name="argv" transfer-ownership="none">
+         <array c:type="gchar**">
+            <type name="utf8"/>
+          </array>
+        </parameter>
+        <parameter name="envp" transfer-ownership="none" allow-none="1">
+          <array c:type="gchar**">
+            <type name="utf8"/>
+          </array>
+        </parameter>
+*
+*
+*<method name="read_line"
+              c:identifier="g_io_channel_read_line"
+              throws="1">
+        <return-value transfer-ownership="none">
+          <type name="IOStatus" c:type="GIOStatus"/>
+        </return-value>
+        <parameters>
+          <parameter name="str_return" transfer-ownership="full" direction="out">
+            <type name="utf8" c:type="gchar**"/>
+          </parameter>
+          <parameter name="length" transfer-ownership="none" direction="out">
+            <type name="gsize" c:type="gsize*"/>
+          </parameter>
+          <parameter name="terminator_pos" transfer-ownership="none"  direction="out">
+            <type name="gsize" c:type="gsize*"/>
+          </parameter>
+        </parameters>
+      </method>
+*
+*
+*
+* 
+*/
+
+
+/**
+ * @class Spawn
+ * @param cfg {Object} settings - see properties.
+ * 
+ * @arg cwd {String}            working directory. (defaults to home directory)
+ * @arg args {Array}            arguments eg. [ 'ls', '-l' ]
+ * @arg listeners {Object} (optional) handlers for output, stderr, input
+ *     stderr/output both receive output line as argument
+ *     input should return any standard input
+ *     finish recieves result as argument.
+ * @arg env {Array}             enviroment eg. [ 'GITDIR=/home/test' ]
+ * @arg async {Boolean} (optional)return instantly, or wait for exit. (default no)
+ * @arg exceptions {Boolean}    throw exception on failure (default no)
+ * @arg debug {Boolean}    print out what's going on.. (default no)
+ * 
+ */
+function Spawn(cfg) {
+    for(var i in cfg) {
+        this[i] = cfg[i];
+    }
+    // set defaults?
+    this.listeners = this.listeners || {};
+    this.cwd =  this.cwd || GLib.get_home_dir();
+    if (!this.args || !this.args.length) {
+        throw "No arguments";
+    }
+    
+}
+
+
+Spawn.prototype = {
+    
+    ctx : false, // the mainloop ctx.
+    listeners : false,
+    async : false,
+    env : null,
+    cwd: false,
+    args: false,
+    exceptions : false,
+    debug : true,
+    /**
+     * @property output {String} resulting output
+     */
+    output  : '',
+    /**
+     * @property stderr {String} resulting output from stderr
+     */
+    stderr  : '',
+     /**
+     * @property result {Number} execution result.
+     */
+    result: 0,
+    /**
+     * @property pid {Number} pid of child process (of false if it's not running)
+     */
+    pid : false,
+    /**
+     * @property in_ch {GLib.IOChannel} input io channel
+     */
+    in_ch : false,
+    /**
+     * @property out_ch {GLib.IOChannel} output io channel
+     */
+    out_ch : false,
+    /**
+     * @property err_ch {GLib.IOChannel} stderr io channel
+     */
+    err_ch : false,
+    /**
+     * 
+     * @method run
+     * Run the configured command.
+     * result is applied to object properties (eg. 'output' or 'stderr')
+     * @returns {Object} self.
+     */
+    run : function()
+    {
+        
+        var _this = this;
+        
+        var err_src = false;
+        var out_src = false;
+        var ret = {};
+        
+        if (this.debug) {
+            print("cd " + this.cwd +";" + this.args.join(" "));
+        }
+        
+        GLib.spawn_async_with_pipes(this.cwd, this.args, this.env, 
+            GLib.SpawnFlags.DO_NOT_REAP_CHILD + GLib.SpawnFlags.SEARCH_PATH , 
+            null, null, ret);
+            
+       //print(JSON.stringify(ret));    
+        this.pid = ret.child_pid;
+        
+        if (this.debug) {
+            print("PID: " + this.pid);
+        }
+        
+        
+       
+        GLib.child_watch_add(GLib.PRIORITY_DEFAULT, this.pid, function(pid, result) {
+            _this.result = result;
+            if (_this.debug) {
+                print("child_watch_add : result: " + result);
+            }
+            _this.read(_this.out_ch);
+            _this.read(_this.err_ch);
+            
+            GLib.spawn_close_pid(_this.pid);
+            _this.pid = false;
+            if (_this.ctx) {
+                _this.ctx.quit();
+            }
+            tidyup();
+           //print("DONE TIDYUP");
+            if (_this.listeners.finish) {
+                _this.listeners.finish.call(this, _this.result);
+            }
+        });
+        
+        function tidyup()
+        {
+            if (_this.pid) {
+                GLib.spawn_close_pid(_this.pid); // hopefully kills it..
+                _this.pid = false;
+            }
+            if (_this.in_ch)  _this.in_ch.close();
+            if (_this.out_ch)  _this.out_ch.close();
+            if (_this.err_ch)  _this.err_ch.close();
+            // blank out channels
+            _this.in_ch = false;
+            _this.err_ch = false;
+            _this.out_ch = false;
+            // rmeove listeners !! important otherwise we kill the CPU
+            if (err_src !== false) GLib.source_remove(err_src);
+            if (out_src !== false) GLib.source_remove(out_src);
+            err_src = false;
+            out_src = false;
+            
+        }
+        
+        
+        this.in_ch = GLib.io_channel_unix_new(ret.standard_input);
+        this.out_ch = GLib.io_channel_unix_new(ret.standard_output);
+        this.err_ch = GLib.io_channel_unix_new(ret.standard_error);
+        
+        // make everything non-blocking!
+        
+        
+      
+         // using NONBLOCKING only works if io_add_watch
+       //returns true/false in right conditions
+       this.in_ch.set_flags (GLib.IOFlags.NONBLOCK);
+       this.out_ch.set_flags (GLib.IOFlags.NONBLOCK);
+       this.err_ch.set_flags (GLib.IOFlags.NONBLOCK);
+         
+
+      
+        // add handlers for output and stderr.
+        out_src= GLib.io_add_watch(this.out_ch, GLib.PRIORITY_DEFAULT, 
+            GLib.IOCondition.OUT + GLib.IOCondition.IN  + GLib.IOCondition.PRI +  GLib.IOCondition.HUP +  GLib.IOCondition.ERR,
+            function() {
+                
+               return  _this.read(_this.out_ch);
+            
+            }
+        );
+        err_src= GLib.io_add_watch(this.err_ch, GLib.PRIORITY_DEFAULT, 
+            GLib.IOCondition.ERR + GLib.IOCondition.IN + GLib.IOCondition.PRI + GLib.IOCondition.OUT +  GLib.IOCondition.HUP, 
+            function()
+        {
+            return _this.read(_this.err_ch);
+             
+        });
+        
+      
+        
+        // call input.. 
+        if (this.pid !== false) {
+            // child can exit before we get this far..
+            if (this.listeners.input) {
+               print("Trying to call listeners");
+                try {
+                    this.write(this.listeners.input.call(this));
+                    // this probably needs to be a bit smarter...
+                   //but... let's close input now..
+                   this.in_ch.close();
+                   _this.in_ch = false;
+                  
+                   
+                   
+                   
+                   
+                } catch (e) {
+                    tidyup();
+                    throw e;
+                    
+                }
+                
+            }
+        }
+        // async - if running - return..
+        if (this.async && this.pid) {
+            return this;
+        }
+        
+        
+        // start mainloop if not async..
+        
+        if (this.pid !== false) {
+            if (this.debug) {
+                print("starting main loop");
+            }
+           
+            this.ctx = new GLib.MainLoop.c_new (null, false);
+            this.ctx.run(false); // wait fore exit?
+            
+            //print("main_loop done!");
+        } else {
+            tidyup(); // tidyup get's called in main loop. 
+        }
+        
+        if (this.exceptions && this.result != 0) {
+            this.toString = function() { return this.stderr; };
+            throw this; // we throw self...
+        }
+        
+        // finally throw, or return self..
+        
+        return this;
+    
+    },
+    /**
+     * write to stdin of process
+     * @arg str {String} string to write to stdin of process
+     * @returns GLib.IOStatus (0 == error, 1= NORMAL)
+     */
+    write : function(str) // write a line to 
+    {
+        if (!this.in_ch) {
+            return 0; // input is closed
+        }
+       //print("write: " + str);
+       // NEEDS GIR FIX! for return value.. let's ignore for the time being..
+       //var ret = {};
+        //var res = this.in_ch.write_chars(str, str.length, ret);
+       var res = this.in_ch.write_chars(str, str.length);
+       
+       //print("write_char retunred:" + JSON.stringify(res) +  ' ' +JSON.stringify(ret)  );
+       
+        if (res != GLib.IOStatus.NORMAL) {
+            throw "Write failed";
+        }
+        //return ret.value;
+        return str.length;
+        
+    },
+    
+    /**
+     * read from pipe and call appropriate listerner and add to output or stderr string.
+     * @arg giochannel to read from.
+     * @returns none
+     */
+    read: function(ch) 
+    {
+        var prop = ch == this.out_ch ? 'output' : 'stderr';
+       // print("prop: " + prop);
+        var _this = this;
+        
+       
+        //print(JSON.stringify(ch, null,4));
+        while (true) {
+            var x =   {};
+            var status = ch.read_line( x);
+            // print('status: '  +JSON.stringify(status));
+            // print(JSON.stringify(x));
+             switch(status) {
+                case GLib.IOStatus.NORMAL:
+               
+                    //write(fn, x.str);
+                    if (this.listeners[prop]) {
+                        this.listeners[prop].call(this, x.str_return);
+                    }
+                    _this[prop] += x.str_return;
+                    if (_this.debug) {
+                        print(prop + ':' + x.str_return.replace(/\n/, ''));
+                    }
+                    if (this.async) {
+                        try {
+                            if (imports.gi.Gtk.events_pending()) {
+                                imports.gi.Gtk.main_iteration();
+                            }
+                        } catch(e) {
+                            
+                        }
+                    }
+                    
+                    //this.ctx.iteration(true);
+                   continue;
+                case GLib.IOStatus.AGAIN:
+                   //print("Should be called again.. waiting for more data..");
+                   return true;
+                    break;
+                case GLib.IOStatus.ERROR:    
+                case GLib.IOStatus.EOF:
+                   return false;
+                   break;
+                
+            }
+            break;
+        }
+       
+        //print("RETURNING");
+         return false; // allow it to be called again..
+    }
+    
+};
+/**
+ * @function run 
+ * 
+ * simple run a process - returns result, or throws stderr result...
+ * @param cfg {Object}  see spawn
+ * @return {string} stdout output.
+ */
+function run(cfg) {
+    cfg.exceptions = true;
+    cfg.async = false;
+    var s = new Spawn(cfg);
+    var ret = s.run();
+    return s.output;
+}
+ /*
+// test
+try { 
+    Seed.print(run({
+        args: ['ls', '/tmp'],
+        debug : true
+    }));
+} catch (e) { print(JSON.stringify(e)); }
+var secs = (new Date()).getSeconds() 
+
+try {      
+Seed.print(run({
+    args: ['/bin/touch', '/tmp/spawntest-' + secs ],
+    debug : true
+}));
+} catch (e) { print( 'Error: ' + JSON.stringify(e)); }
+
+ */
diff --git a/StatusIcon.js b/StatusIcon.js
new file mode 100644 (file)
index 0000000..190bcf4
--- /dev/null
@@ -0,0 +1,239 @@
+/**
+ * Status icon and menu for component of gitlive.
+ * 
+ * Implements XObject - however we want to control initialization.
+ * 
+ * 
+ * 
+ * Currently only does a few things
+ * a) Quit
+ * 
+ * b) Pause!??!
+ */
+var Gtk      = imports.gi.Gtk;
+var Gdk      = imports.gi.Gdk;
+var Gio      = imports.gi.Gio;
+var GLib     = imports.gi.GLib;
+var Notify   = imports.gi.Notify;
+
+var XObject = imports.XObject.XObject;
+
+//var gitlive = imports.gitlive;
+
+var StatusIcon  = new XObject({
+    
+    paused : false, // on!
+    xtype : Gtk.StatusIcon,
+    title : 'gitlive',
+    stock : Gtk.STOCK_MEDIA_PLAY,
+    tooltip_text : 'GitLive',
+        init : function() {
+        XObject.prototype.init.call(this);
+        this.el.set_name('gitlive');
+    },
+    listeners : {
+        //'popup-menu' : function( w, event, event_time) {
+        'activate' : function( w, event, event_time) {
+            print(Array.prototype.slice.call(arguments).join(','));
+            
+            var menu = this.get('menu');
+            
+            menu.el.show_all();
+            
+            this.get(!this.paused ? 'resume' : 'pause' ).el.hide();
+            
+            menu.el.popup(null, null,Gtk.StatusIcon.position_menu , this.el , 1, Gtk.get_current_event_time());
+            //menu.el.popup(null, null,null, null, 1, Gtk.get_current_event_time());
+            
+            return;
+            
+            var g = { };
+            var a = new Gdk.Rectangle();
+            //  needs direction=inout setting in gir to work (in bugzilla @present)
+            this.el.get_geometry(g,a,null);
+             
+            // should check to see if @ top or bottom I guess..
+            menu.el.get_toplevel().move(a.x, a.y +a.height);
+             
+        }
+    },
+    items : [
+       {
+            xtype: Gtk.Menu,
+            id : 'menu',
+            pack: false,
+            items : [
+                {
+                    init : function() {
+                        this.el = new Gtk.ImageMenuItem.from_stock(Gtk.STOCK_MEDIA_PAUSE);
+                        XObject.prototype.init.call(this);
+                    },
+                    label: 'Pause Commits',
+                   
+                    always_show_image : true,
+                    accel_group : null,
+                    id : 'pause',
+                    //label: 'Pause',
+                    pack:  'append',
+                    listeners : {
+                        activate : function () {
+                            this.parent.parent.paused = true;
+                            imports.gitlive.monitor.stop();
+                           // this.el.label  = status ? 'Resume' : 'Pause';
+                            this.parent.parent.el.set_from_stock( Gtk.STOCK_MEDIA_PAUSE );
+                            
+                        }
+                    }
+                },
+                
+                {
+                    init : function() {
+                        this.el = new Gtk.ImageMenuItem.from_stock(Gtk.STOCK_MEDIA_PLAY);
+                        XObject.prototype.init.call(this);
+                    },
+                    label: 'Resume Commits',
+                    always_show_image : true,
+                    accel_group : null,
+                    id : 'resume',
+                    //label: 'Pause',
+                    pack:  'append',
+                    listeners : {
+                        activate : function () {
+                            this.parent.parent.paused = false;
+                            imports.gitlive.monitor.start();
+                            //var status = this.el.label == 'Pause' ? 1 : 0
+                           // this.el.label  = status ? 'Resume' : 'Pause';
+                            this.parent.parent.el.set_from_stock(   Gtk.STOCK_MEDIA_PLAY);
+                            
+                        }
+                    }
+                },
+                
+                {
+                    init : function() {
+                        this.el = new Gtk.ImageMenuItem.from_stock(Gtk.STOCK_RELOAD);
+                        XObject.prototype.init.call(this);
+                    },
+                    label: 'Pull (Refresh) All',
+                    always_show_image : true,
+                    accel_group : null,
+                    //label: 'Pause',
+                    pack:  'append',
+                    listeners : {
+                        activate : function () {
+                            imports.gitlive.monitor.stop();
+                            
+                            var f = Gio.file_new_for_path(imports.GitMonitor.GitMonitor.gitlive);
+                            var file_enum = f.enumerate_children(
+                                Gio.FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, Gio.FileQueryInfoFlags.NONE, null);
+
+                            var next_file = null;
+                            
+                            while ((next_file = file_enum.next_file(null)) != null) {
+                                
+                                var fn = imports.GitMonitor.GitMonitor.gitlive + '/' + next_file.get_display_name();
+                                if (! GLib.file_test(fn + '/.git', GLib.FileTest.IS_DIR)) {
+                                    continue;
+                                }
+                                
+                                var repo = new imports.Scm.Git.Repo.Repo({
+                                    repopath : fn
+                                });
+                                try { 
+                                    var str = repo.pull(); 
+                                    var notification = new Notify.Notification({
+                                       summary: "Updated " + fn,
+                                       body : res.output
+                                   });
+                                   notification.set_timeout(20);
+                                   notification.show();
+                                   
+                                } catch(e) {
+                                    print(JSON.stringify(e));
+                                    print("notification or push errror- probably to many in queue..");
+                                    imports.gitlive.errorDialog(e.message);
+
+                                }
+                                
+                                    // should also update modules ideally.
+                                
+                            }
+                            
+                                
+                            file_enum.close(null);
+
+                            
+                            imports.GitMonitor.GitMonitor.start();
+                            
+                        }
+                    }
+                },
+                {
+                    init : function() {
+                        this.el = new Gtk.ImageMenuItem.from_stock(Gtk.STOCK_RELOAD);
+                        XObject.prototype.init.call(this);
+                    },
+                    label: 'Manage Clones',
+                    always_show_image : true,
+                    accel_group : null,
+                    
+                    //label: 'Pause',
+                    pack:  'append',
+                    listeners : {
+                        activate : function () {
+                             var ret = imports.Clones.Clones.show();
+                            
+                        }
+                    }
+                },
+                
+                
+                
+            
+                {
+                    init : function() {
+                        this.el = new Gtk.ImageMenuItem.from_stock(Gtk.STOCK_ABOUT);
+                        XObject.prototype.init.call(this);
+                    },
+                    label: 'About GitLive',
+                    pack:  'append',
+                    listeners : {
+                        activate : function () {
+                            var msg = new Gtk.AboutDialog({
+                                program_name : "Git Live",
+                                version: '0.3',
+                                website: 'http://www.roojs.org/index.php/projects/gitlive.html',
+                                website_label: 'RooJS Consulting',
+                                license : 'LGPL'
+                            });
+                            msg.set_authors([ "Alan Knowles <alan@roojs.com>" ]);
+                            msg.run();
+                            msg.destroy();
+                        }
+                    }
+                },
+                
+                {
+                    init : function() {
+                        this.el = new Gtk.ImageMenuItem.from_stock(Gtk.STOCK_QUIT);
+                        XObject.prototype.init.call(this);
+                    },
+                    label: 'Quit',
+                    pack:  'append',
+                    listeners : {
+                        activate : function () {
+                            Seed.quit();
+                        }
+                    }
+                }
+                
+                
+            ]
+        }
+    ]
+    
+});
+
+
diff --git a/WindowLog.js b/WindowLog.js
new file mode 100644 (file)
index 0000000..39772ef
--- /dev/null
@@ -0,0 +1,34 @@
+//<script type="text/javascript">
+/**
+ * log desktop actions..
+ *
+ * a potential add-on to gitlive....
+ * - basically tracks what applications are being worked on when, allowing you to
+ * use it to generate time tracking (eg. invoices...) later..
+ * 
+ * mouse:
+ * xdotool getmouselocation
+ *
+ * xwit -property WM_NAME -print 
+ * 0x3a13d6c: x=1 y=25 w=1109 h=747 d=32 'root@wideboy: /home/alan'
+ * root@wideboy:/home/alan# xwit -property WM_CLASS -print 
+ * 0x3a13d6c: x=1 y=25 w=1109 h=747 d=32 'gnome-terminal'
+ * root@wideboy:/home/alan# 
+ * 
+ * 
+ * Not sure how we handle last key press...
+ * 
+ * -- log to a remote url.
+ * 
+ * LOG:
+ * DATE / TIME / Application / Title
+ * if cursor same as before.. - SEND 'IDLE'... (twice, then stop sending..)
+ * 
+ * For commits... (we send out every 1 minute as well, it's upto the other end to determine if that means updating
+ * or creating a new record..
+ * yyyy-mm-dd /12:00 / GIT / XXXXX
+ * 
+ */
+
+
+
diff --git a/XObject.js b/XObject.js
new file mode 100644 (file)
index 0000000..3064ac3
--- /dev/null
@@ -0,0 +1,666 @@
+//<script type="text/javascript">
+var GIRepository = imports.gi.GIRepository;
+var GObject = imports.gi.GObject;
+/**
+ * XObject
+ * Yet another attempt to create a usable object construction library for seed..
+ * 
+ * Why is this useful?
+ * A) It turns rather messy code into a tree structure, making it easy to find code relating to 
+ *    an interface element
+ * B) In theory it should be gjs/Seed compatible..
+ * C) It provides getElementById style lookups for elements.
+ * D) It provides classic OO constructors for Javascript (extend/define)
+ * E) It does not modify any buildin prototypes.. 
+ *
+ * Extend this.. to use it's wonderful features..
+ * 
+ * normal usage:
+ * XObject = imports.XObject.XObject;
+ * 
+ * Xyz = new XObject({
+ *     xtype: Gtk.Window,
+ *     id : 'window',
+ *     items : [
+ *     
+ *     ]
+ *  });
+ *  Xyz.init(); // create and show.
+ * 
+ * 
+ * 
+ * @arg xtype {String|Function} constructor or string.
+ * @arg id {String}  (optional) id for registry
+ * @arg xns {String|Object}   (optional) namespace eg. Gtk or 'Gtk' - used with xtype.
+ * @arg items {Array}   (optional) list of child elements which will be constructed.. using XObject
+ * @arg listeners {Object}   (optional) map Gobject signals to functions
+ * @arg pack {Function|String|Array}   (optional) how this object gets added to it's parent
+ * @arg el {Object}   (optional) premade GObject
+ * 
+ *  --- needs a xdebug option!
+ * 
+ * 
+ * He's some questions.
+ * - should we generate ID's for all elements? (if so we probably need to garbage collect)
+ * - should we have a special property to use as the constructor / gobject.properties rather
+ *   than sending all basic types to this?
+ * 
+ * 
+ */
+
+function XObject (cfg) {
+    // first apply cfg if set.
+      //print("new XOBJECT!!!");
+    this.config = {};
+    this.constructor = XObject;
+    
+    // copy down all elements into self..
+    
+    for (var i in cfg) {
+        this[i] = cfg[i];
+        if (typeof(cfg[i]) == 'function') { // do we skip objects.
+            continue;
+        }
+        // these properties are not copied to cfg.
+        if (    i == 'pack' ||
+                i == 'items' ||
+                i == 'id' ||
+                i == 'xtype' ||
+                i == 'xdebug' ||
+                i == 'xns') {
+            continue;
+        }
+        
+        
+        this.config[i] = cfg[i];
+    }
+    this.items = this.items || [];
+    // pack can be false!
+    if (typeof(this.pack) == 'undefined') {
+        
+        this.pack = [ 'add' ]
+        /*
+        var Gtk  = imports.gi.Gtk;
+        switch (true) {
+            // any others!!
+            case (this.xtype == Gtk.MenuItem):  this.pack = [ 'append' ]; break;
+            
+        }
+        */
+        
+    }
+    
+    
+    
+}
+
+
+
+XObject.prototype = {
+    /**
+     * @property el {GObject} the Gtk / etc. element.
+     */
+    el : false, 
+    /*
+     * @property items {Array} list of sub elements
+     */
+    /**
+     * @property parent {XObject} parent Element
+     */
+     
+     /**
+     * @property config {Object} the construction configuration.
+     */
+     /**
+      * @method init
+      * Initializes the Element (el) hooks up all the listeners
+      * and packs the children.
+      * you can override this, in child objects, then 
+      * do this to do thi initaliztion.
+      * 
+      * XObject.prototype.init.call(this); 
+      * 
+      */ 
+    init : function()
+    {
+         
+        var items = [];
+        this.items.forEach(function(i) {
+            items.push(i);
+        });
+        // remove items.
+        this.listeners = this.listeners || {}; 
+        this.items = [];
+         
+        // do we need to call 'beforeInit here?'
+         
+        // handle include?
+        //if ((this.xtype == 'Include')) {
+        //    o = this.pre_registry[cls];
+        //}
+        var isSeed = typeof(Seed) != 'undefined';
+         
+        // xtype= Gtk.Menu ?? what about c_new stuff?
+        if (XObject.debug) print("init: ID:"+ this.id +" typeof(xtype): "  + typeof(this.xtype));
+        if (!this.el && typeof(this.xtype) == 'function') {
+            // gjs implements xtype as function in seed they are undefined..
+            if (XObject.debug) print("func?"  + XObject.keys(this.config).join(','));
+            try {
+                this.el = this.xtype(this.config);
+            } catch(e) {
+                this.el = false;
+            }
+            
+           
+        }
+        if (!this.el && typeof(this.xtype) == 'object') {
+            if (XObject.debug) print("obj?"  + XObject.keys(this.config).join(','));
+            this.el = new (this.xtype)(this.config);
+      
+        }
+        //print(this.el);
+        if (!this.el && this.xns) {
+            
+            var NS = imports.gi[this.xns];
+            if (!NS) {
+                Seed.print('Invalid xns: ' + this.xns);
+            }
+            constructor = NS[this.xtype];
+            if (!constructor) {
+                Seed.print('Invalid xtype: ' + this.xns + '.' + this.xtype);
+            }
+            this.el  =   isSeed ? new constructor(this.config) : new constructor();
+            
+        }
+        if (XObject.debug) print("init: ID:"+ this.id +" typeof(el):" + this.el);
+        
+        // always overlay props..
+        // check for 'write' on object..
+        /*
+        if (typeof(XObject.writeablePropsCache[this.xtype.type]) == 'undefined') {
+                
+            var gi = GIRepository.IRepository.get_default();
+            var ty = gi.find_by_gtype(this.xtype.type);
+            var write = [];
+            for (var i =0; i < GIRepository.object_info_get_n_properties(ty);i++) {
+                var p =   GIRepository.object_info_get_property(ty,i);
+                if (GIRepository.property_info_get_flags(p) & 2) {
+                    write.push(GIRepository.base_info_get_name(p));
+                }
+            }
+            XObject.writeablePropsCache[this.xtype.type] = write;
+            print(write.join(", "));
+        }
+        
+        */
+        
+         
+        for (var i in this.config) {
+            if (i == 'type') { // problem with Gtk.Window... - not decided on a better way to handle this.
+                continue;
+            }
+            if (i == 'buttons') { // problem with Gtk.MessageDialog..
+                continue;
+            }
+            if (i[0] == '.') { // parent? - 
+                continue;
+            }
+            this.el[i] = this.config[i];
+        }
+        
+        // register it!
+        //if (o.xnsid  && o.id) {
+         //   XObject.registry = XObject.registry || { };
+         //   XObject.registry[o.xnsid] = XObject.registry[o.xnsid] || {}; 
+         //   XObject.registry[o.xnsid][o.id] = this;
+        //}
+        
+        var type = this.xtype && this.xtype.type ? GObject.type_name(this.xtype.type) : '';
+        print("MAKE " + type);
+        
+        
+        var _this=this;
+        items.forEach(function(i,n) {
+            
+            if (type == 'GtkTable' && i.pack == 'add') {
+                var c = n % _this.config.n_columns;
+                var r = Math.floor(n/_this.config.n_columns);
+                i.pack = [ 'attach', c, c+1, r, r+1, 
+                        typeof(i.x_options) == 'undefined' ?  5 : i.x_options,
+                        typeof(i.y_options) == 'undefined' ?  5 : i.y_options,
+                        typeof(i.x_padding) == 'undefined' ?  0 : i.x_padding,
+                        typeof(i.x_padding) == 'undefined' ?  0 : i.x_padding
+                       
+                ]
+            }
+            
+            _this.addItem(i);
+        })
+            
+        
+        for (var i in this.listeners) {
+            this.addListener(i, this.listeners[i]);
+        }
+        
+        // delete this.listeners ?
+        // do again so child props work!
+       
+        // do we need to call 'init here?'
+    },
+      
+     /**
+      * @method addItem
+      * Adds an item to the object using a new XObject
+      * uses pack property to determine how to add it.
+      * @arg cfg {Object} same as XObject constructor.
+      */
+    addItem : function(o) {
+        if (typeof(o) == 'undefined') {
+            print("Invalid Item added to this!");
+            imports.console.dump(this);
+            Seed.quit();
+        }
+        // what about extended items!?!?!?
+        var item = (o.constructor == XObject) ? o : new XObject(o);
+        item.parent = this;
+        this.items.push(item);
+        item.init();
+        //print("CTR:PROTO:" + ( item.id ? item.id : '??'));
+       // print("addItem - call init [" + item.pack.join(',') + ']');
+        if (!item.el) {
+            print("NO EL!");
+            imports.console.dump(item);
+            Seed.quit();
+        }
+         
+        
+        if (item.pack===false) {  // no 
+            return;
+        }
+        if (typeof(item.pack) == 'function') {
+            // parent, child
+            item.pack.apply(item, [ this , item  ]);
+            item.parent = this;
+            return;
+        }
+        var args = [];
+        var pack_m  = false;
+        if (typeof(item.pack) == 'string') {
+             
+            item.pack.split(',').forEach(function(e, i) {
+                
+                if (e == 'false') { args.push( false); return; }
+                if (e == 'true') {  args.push( true);  return; }
+                if (!isNaN(parseInt(e))) { args.push( parseInt(e)); return; }
+                args.push(e);
+            });
+            //print(args.join(","));
+            
+            pack_m = args.shift();
+        } else {
+            pack_m = item.pack.shift();
+            args = item.pack;
+        }
+        
+        // handle error.
+        if (pack_m && typeof(this.el[pack_m]) == 'undefined') {
+            
+            throw {
+                name: "ArgumentError", 
+                message : 'pack method not available : ' + this.id + " : " + this.xtype + '.' +  pack_m + " ADDING " + item.el
+                    
+            }
+           
+            
+            
+            
+            return;
+        }
+        
+        
+        //Seed.print('Pack ' + this.el + '.'+ pack_m + '(' + item.el + ')');
+
+        args.unshift(item.el);
+        if (XObject.debug) print(pack_m + '[' + args.join(',') +']');
+        //Seed.print('args: ' + args.length);
+        if (pack_m) {
+            this.el[pack_m].apply(this.el, args);
+        }
+        
+       
+        
+    },
+    /**
+      * @method addListener
+      * Connects a method to a signal. (gjs/Seed aware)
+      * 
+      * @arg sig  {String} name of signal
+      * @arg fn  {Function} handler.
+      */
+    addListener  : function(sig, fn) 
+    {
+        if (XObject.debug) Seed.print("Add signal " + sig);
+        fn.id= sig;
+        var _li = XObject.createDelegate(fn,this);
+        // private listeners that are not copied to GTk.
+        
+        if (typeof(Seed) != 'undefined') {
+          //   Seed.print(typeof(_li));
+            this.el.signal[sig].connect(_li);
+        } else {
+            this.el.connect( sig, _li);
+        }
+             
+        
+    },
+     /**
+      * @method get
+      * Finds an object in the child elements using xid of object.
+      * prefix with '.' to look up the tree.. 
+      * prefix with multiple '..' to look further up..
+      * prefix with '/' to look from the top, eg. '^LeftTree.model'
+      * 
+      * @arg name  {String} name of signal
+      * @return   {XObject|false} the object if found.
+      */
+    get : function(xid)
+    {
+        if (XObject.debug) print("SEARCH FOR " + xid + " in " + this.id);
+        var ret=  false;
+        var oid = '' + xid;
+        if (!xid.length) {
+            throw {
+                name: "ArgumentError", 
+                message : "ID not found : empty id"
+            }
+        }
+        
+        if (xid[0] == '.') {
+            return this.parent.get(xid.substring(1));
+        }
+        if (xid[0] == '/') {
+            
+            if (typeof(XObject.cache[xid]) != 'undefined') {
+                return XObject.cache[xid]; 
+            }
+            if (xid.indexOf('.') > -1) {
+                
+                var child = xid.split('.');
+                var nxid = child.shift();
+                    
+                child = child.join('.');
+                if (typeof(XObject.cache[nxid]) != 'undefined') {
+                    return XObject.cache[nxid].get(child);
+                }
+                
+                
+            }
+            var e = this;
+            while (e.parent) {
+                e = e.parent;
+            }
+            
+            try {
+                ret = e.get(xid.substring(1));
+            } catch (ex) { }
+            
+            if (!ret) {
+                throw {
+                    name: "ArgumentError", 
+                    message : "ID not found : " + oid
+                }
+            }
+            XObject.cache[xid] = ret;
+            return XObject.cache[xid];
+        }
+        var child = false;
+        
+        if (xid.indexOf('.') > -1) {
+            child = xid.split('.');
+            xid = child.shift();
+            
+            child = child.join('.');
+            
+        }
+        if (xid == this.id) {
+            try {
+                return child === false ? this : this.get(child);
+            } catch (ex) {
+                throw {
+                    name: "ArgumentError", 
+                    message : "ID not found : " + oid
+                }
+            }
+            
+        }
+        
+        
+        this.items.forEach(function(ch) {
+            if (ret) {
+                return;
+            }
+            if (ch.id == xid) {
+                ret = ch;
+            }
+        })
+        if (ret) {
+            try {
+                return child === false ? ret : ret.get(child);
+            } catch (ex) {
+                throw {
+                    name: "ArgumentError", 
+                    message : "ID not found : " + oid
+                }
+            }
+            
+        }
+        // iterate children.
+        var _this = this;
+        this.items.forEach(function(ch) {
+            if (ret) {
+                return;
+            }
+            if (!ch.get) {
+                print("invalid item...");
+                imports.console.dump(_this);
+                Seed.quit();
+            }
+            try {
+                ret = ch.get(xid);
+            } catch (ex) { }
+            
+            
+        });
+        if (!ret) {
+            throw {
+                name: "ArgumentError", 
+                message : "ID not found : " + oid
+            }
+        }
+        try {
+            return child === false ? ret : ret.get(child);
+        } catch (ex) {
+            throw {
+                name: "ArgumentError", 
+                message : "ID not found : " + oid
+            }
+        }
+    }
+      
+      
+} 
+         
+     
+/**
+ * Copies all the properties of config to obj.
+ *
+ * Pretty much the same as JQuery/Prototype..
+ * @param {Object} obj The receiver of the properties
+ * @param {Object} config The source of the properties
+ * @param {Object} defaults A different object that will also be applied for default values
+ * @return {Object} returns obj
+ * @member XObject extend
+ */
+
+
+XObject.extend = function(o, c, defaults){
+    if(defaults){
+        // no "this" reference for friendly out of scope calls
+        XObject.extend(o, defaults);
+    }
+    if(o && c && typeof c == 'object'){
+        for(var p in c){
+            o[p] = c[p];
+        }
+    }
+    return o;
+};
+
+XObject.extend(XObject,
+{
+     
+    /**
+     * @property {Boolean} debug XObject  debugging.  - set to true to debug.
+     * 
+     */
+    debug : true,
+    /**
+     * @property {Object} cache - cache of object ids
+     * 
+     */
+    cache: { },
+    
+    /**
+     * Copies all the properties of config to obj, if the do not exist.
+     * @param {Object} obj The receiver of the properties
+     * @param {Object} config The source of the properties
+     * @return {Object} returns obj
+     * @member Object extendIf
+     */
+
+
+    extendIf : function(o, c){
+
+        if(!o || !c || typeof c != 'object'){
+            return o;
+        }
+        for(var p in c){
+            if (typeof(o[p]) != 'undefined') {
+                continue;
+            }
+            o[p] = c[p];
+        }
+        return o;
+    },
+
+
+    /**
+     * Extends one class with another class and optionally overrides members with the passed literal. This class
+     * also adds the function "override()" to the class that can be used to override
+     * members on an instance.
+     *
+     * usage:
+     * MyObject = XObject.define(
+     *     function(...) {
+     *          ....
+     *     },
+     *     parentClass, // or Object
+     *     {
+     *        ... methods and properties.
+     *     }
+     * });
+     * @param {Function} constructor The class inheriting the functionality
+     * @param {Object} superclass The class being extended
+     * @param {Object} overrides (optional) A literal with members
+     * @return {Function} constructor (eg. class
+     * @method define
+     */
+    define : function(){
+        // inline overrides
+        var io = function(o){
+            for(var m in o){
+                this[m] = o[m];
+            }
+        };
+        return function(constructor, parentClass, overrides) {
+            if (typeof(parentClass) == 'undefined') {
+                print("XObject.define: Missing parentClass: when applying: " );
+                print(new String(constructor));
+                Seed.quit(); 
+            }
+            if (typeof(parentClass.prototype) == 'undefined') {
+                print("Missing protype: when applying: " );
+                print(new String(constructor));
+                print(new String(parentClass));
+                Seed.quit(); 
+            }
+            var F = function(){};
+            var sbp;
+            var spp = parentClass.prototype;
+            
+            F.prototype = spp;
+            sbp = constructor.prototype = new F();
+            sbp.constructor=constructor;
+            constructor.superclass=spp;
+
+            // extends Object.
+            if(spp.constructor == Object.prototype.constructor){
+                spp.constructor=parentClass;
+            }
+            
+            constructor.override = function(o){
+                Object.extend(constructor.prototype, o);
+            };
+            sbp.override = io;
+            XObject.extend(constructor.prototype, overrides);
+            return constructor;
+        };
+    }(),
+
+         
+    /**
+     * returns a list of keys of the object.
+     * @param {Object} obj object to inspect
+     * @return {Array} returns list of kyes
+     * @member XObject keys
+     */
+    keys : function(o)
+    {
+        var ret = [];
+        for(var i in o) {
+            ret.push(i);
+        }
+        return ret;
+    },
+      
+    /**
+     * @member XObject createDelegate
+     * creates a delage metdhod
+     * @param {Function} method to wrap
+     * @param {Object} scope 
+     * @param {Array} args to add
+     * @param {Boolean|Number} append arguments or replace after N arguments.
+     * @return {Function} returns the delegate
+     */
+
+    createDelegate : function(method, obj, args, appendArgs){
+        
+        return function() {
+            if (XObject.debug) print("CALL: " + obj.id + ':'+ method.id);
+            
+            var callArgs = args || arguments;
+            if(appendArgs === true){
+                callArgs = Array.prototype.slice.call(arguments, 0);
+                callArgs = callArgs.concat(args);
+            }else if(typeof appendArgs == "number"){
+                callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
+                    var applyArgs = [appendArgs, 0].concat(args); // create method call params
+                    Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
+                }
+                return method.apply(obj || window, callArgs);
+            };
+    }
+    
+});
\ No newline at end of file
diff --git a/git_tool_notes.txt b/git_tool_notes.txt
new file mode 100644 (file)
index 0000000..ab300d9
--- /dev/null
@@ -0,0 +1,44 @@
+
+
+idea:
+
+- local version of merger -
+* it basically shows the difference between two branches,
+as a tree, then as a list of changed files, then diff view
+
+- to do this.
+
+A) select repo 
+ current directory (eg.) 'Repo' Class
+B) get history
+  ....
+C) get diff etc...
+
+Lets' start with the Repo directory.
+
+
+Design
+
+Top bar:
+- select repo (done by manage repos)
+- select "Release Branch" 
+- select "Working Branch"
+
+
+
+
+
+
+----
+Other dialogs
+
+Manage Repos
+-> list of repo's
+
+Actions:
+-> Merger
+-> Pull branches (from remote)
+-> Add?
+-> Flag 'auto-commit'
+-> Flag 'auto-push'
+-> Switch Branch
\ No newline at end of file
diff --git a/gitlive.js b/gitlive.js
new file mode 100644 (file)
index 0000000..5bcf0ca
--- /dev/null
@@ -0,0 +1,74 @@
+#!/usr/bin/seed
+///<script type="text/javascript">
+/**
+* Git Live
+* 
+* inotify hooks for ~/gitlive
+* that commit and push any changes made.
+* Bit like a revision controled backed up file system!?
+* 
+* 
+*/
+
+GIRepository      = imports.gi.GIRepository
+GLib        = imports.gi.GLib;
+
+//print(JSON.stringify(GI, null,4));
+// we add this in, as it appears to get lost sometimes if we set it using the ENV. variable in builder.sh
+// see the install instructions on how to override the default gir's
+GIRepository.Repository.prepend_search_path(GLib.get_home_dir() + '/.Builder/girepository-1.2');
+
+var Gio      = imports.gi.Gio;
+var Gtk      = imports.gi.Gtk;
+var Notify   = imports.gi.Notify;
+var StatusIcon  = imports.StatusIcon.StatusIcon;
+var Monitor     = imports.Monitor.Monitor;
+var GitMonitor  = imports.GitMonitor.GitMonitor;
+
+
+Gtk.init (null, null);
+
+// sanity check...
+
+// where is everything..
+GitMonitor.gitlive =  GLib.get_home_dir() + "/gitlive";
+
+if (!GLib.file_test(GitMonitor.gitlive, GLib.FileTest.IS_DIR)) {
+    var msg = new Gtk.MessageDialog({message_type:
+        Gtk.MessageType.INFO, buttons : Gtk.ButtonsType.OK, text: "GIT Live - ~/gitlive does not exist."});
+    msg.run();
+    msg.destroy();
+    Seed.quit();
+}
+// I'm lost...
+
+function errorDialog(data) {
+    var msg = new Gtk.MessageDialog({
+            message_type: Gtk.MessageType.ERROR, 
+            buttons : Gtk.ButtonsType.OK, 
+            text: data
+    });
+    msg.run();
+    msg.destroy();
+}
+
+
+
+//
+// need a better icon...
+
+
+StatusIcon.init();   
+
+
+Notify.init("gitlive");
+
+GitMonitor.add(GitMonitor.gitlive);
+GitMonitor.start();
+
+Gtk.main();
+vv//icon.signal["activate"].connect(on_left_click);