diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index 090c6ac092d..870f3494320 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -9,10 +9,7 @@ import openerpweb import openerpweb.ast import openerpweb.nonliterals -__all__ = ['Session', 'Menu', 'DataSet', 'View', - 'FormView', 'ListView', 'SearchView', - 'Action'] - +# Should move to openerpweb.Xml2Json class Xml2Json: # xml2json-direct # Simple and straightforward XML-to-JSON converter in Python @@ -276,12 +273,9 @@ class DataSet(openerpweb.Controller): return {'fields': req.session.model(model).fields_get()} @openerpweb.jsonrequest - def find(self, request, model, fields=False, offset=0, limit=False, - domain=None, context=None, sort=None): - return self.do_find(request, model, fields, offset, limit, - domain, context, sort) - def do_find(self, request, model, fields=False, offset=0, limit=False, - domain=None, context=None, sort=None): + def search_read(self, request, model, fields=False, offset=0, limit=False, domain=None, context=None, sort=None): + return self.do_search_read(request, model, fields, offset, limit, domain, context, sort) + def do_search_read(self, request, model, fields=False, offset=0, limit=False, domain=None, context=None, sort=None): """ Performs a search() followed by a read() (if needed) using the provided search criteria @@ -464,7 +458,6 @@ class FormView(View): fields_view = self.fields_view_get(req.session, model, view_id, 'form') return {'fields_view': fields_view} - class ListView(View): _cp_path = "/base/listview" @@ -473,7 +466,6 @@ class ListView(View): fields_view = self.fields_view_get(req.session, model, view_id, 'tree') return {'fields_view': fields_view} - class SearchView(View): _cp_path = "/base/searchview" @@ -491,7 +483,6 @@ class SideBar(View): [[model, object_id]], False, {}) return result - class Action(openerpweb.Controller): _cp_path = "/base/action" diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js index 761ff532f1b..db2db6b91e5 100644 --- a/addons/base/static/src/js/chrome.js +++ b/addons/base/static/src/js/chrome.js @@ -468,9 +468,24 @@ openerp.base.Controller = openerp.base.BasicController.extend( /** @lends opener }); openerp.base.CrashManager = openerp.base.Controller.extend({ -// Controller to display exception and stacktrace and eventually report error trought maitenance contract -// if should hook on Session.on_rpc_error: function(error) { -// and display OPW etc... + init: function(session, element_id) { + this._super(session, element_id); + this.session.on_rpc_error.add(this.on_rpc_error); + }, + on_rpc_error: function(error) { + var msg = error.message + "\n" + error.data.debug; + this.display_error(msg); + }, + display_error: function(message) { + $('
').text(message).dialog({
+            modal: true,
+            buttons: {
+                OK: function() {
+                    $(this).dialog("close");
+                }
+            }
+        });
+    }
 });
 
 openerp.base.Database = openerp.base.Controller.extend({
@@ -677,6 +692,7 @@ openerp.base.WebClient = openerp.base.Controller.extend({
 
         this.session = new openerp.base.Session("oe_errors");
         this.loading = new openerp.base.Loading(this.session, "oe_loading");
+        this.crashmanager =  new openerp.base.CrashManager(this.session);
 
         // Do you autorize this ?
         openerp.base.Controller.prototype.notification = new openerp.base.Notification(this.session, "oe_notification");
diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js
index 059b24af232..6c82d79e00f 100644
--- a/addons/base/static/src/js/data.js
+++ b/addons/base/static/src/js/data.js
@@ -29,55 +29,119 @@ openerp.base.DataSet =  openerp.base.Controller.extend( /** @lends openerp.base.
     init: function(session, model) {
         this._super(session);
         this.model = model;
-
-        this.ids = [];
-        this.offset
+        this.context = {};
         this.index = 0;
         this.count = 0;
-
-        this.sort = [];
-        this.domain = [];
-        this.context = {};
     },
     start: function() {
     },
-
     previous: function () {
         this.index -= 1;
         if (this.index < 0) {
-            this.index = this.ids.length - 1;
+            this.index = this.count - 1;
         }
         return this;
     },
     next: function () {
         this.index += 1;
-        if (this.index >= this.ids.length) {
+        if (this.index >= this.count) {
             this.index = 0;
         }
         return this;
     },
-
+    /**
+     * Read records.
+     */
+    read_ids: function (ids, fields, callback) {
+        var self = this;
+        this.rpc('/base/dataset/get', {
+            model: this.model,
+            ids: ids,
+            fields: fields
+        }, callback);
+    },
+    /**
+     * Read a slice of the records represented by this DataSet, based on its
+     * domain and context.
+     *
+     * @param {Number} [offset=0] The index from which selected records should be returned
+     * @param {Number} [limit=null] The maximum number of records to return
+     */
+    read_slice: function (fields, offset, limit, callback) {
+    },
+    /**
+     * Read the indexed record.
+     */
+    read_index: function (fields, callback) {
+        if (_.isEmpty(this.ids)) {
+            callback([]);
+        } else {
+            fields = fields || false;
+            this.read_ids([this.ids[this.index]], fields, function(records) {
+                callback(records[0]);
+            });
+        }
+    },
     default_get: function() {
     },
     create: function() {
     },
-    /**
-     * Fetch all the records selected by this DataSet, based on its domain
-     * and context.
-     *
-     * Fires the on_ids event.
-     *
-     * TODO: return deferred
-     *
-     * @param {Number} [offset=0] The index from which selected records should be returned
-     * @param {Number} [limit=null] The maximum number of records to return
-     * @returns itself
-     */
-    // Rename into read() ?
-    fetch: function (fields, offset, limit, callback) {
+    write: function (id, data, callback) {
+        this.rpc('/base/dataset/save', {
+            model: this.model,
+            id: id,
+            data: data,
+            context: this.context
+        }, callback);
+    },
+    unlink: function() {
+    },
+    call: function (method, ids, args, callback) {
+        ids = ids || [];
+        args = args || [];
+        this.rpc('/base/dataset/call', {
+            model: this.model,
+            method: method,
+            ids: ids,
+            args: args
+        }, callback);
+    },
+});
+
+openerp.base.DataSetStatic =  openerp.base.DataSet.extend({
+    init: function(session, model, ids) {
+        this._super(session, model);
+        // all local records
+        this.ids = ids;
+        this.count = ids.length;
+    },
+    read_slice: function (fields, offset, limit, callback) {
+        this.read_ids(this.ids.slice(offset, offset + limit));
+    },
+});
+
+openerp.base.DataSetSearch =  openerp.base.DataSet.extend({
+    init: function(session, model) {
+        this._super(session, model);
+        this.domain = [];
+        this.sort = [];
+        this.offset = 0;
+        // subset records[offset:offset+limit]
+        // is it necessary ?
+        this.ids = [];
+    },
+    read_slice: function (fields, offset, limit, callback) {
         var self = this;
         offset = offset || 0;
-        this.rpc('/base/dataset/find', {
+        // cached search, not sure it's a good idea
+        if(this.offset <= offset) {
+            var start = offset - this.offset;
+            if(this.ids.length - start >= limit) {
+                // TODO: check if this could work do only read if possible
+                // return read_ids(ids.slice(start,start+limit),fields,callback)
+            }
+        }
+        this.rpc('/base/dataset/search_read', {
             model: this.model,
             fields: fields,
             domain: this.domain,
@@ -94,50 +158,6 @@ openerp.base.DataSet =  openerp.base.Controller.extend( /** @lends openerp.base.
             callback(records);
         });
     },
-    fetch_ids: function (ids, fields, callback) {
-        var self = this;
-        this.rpc('/base/dataset/get', {
-            model: this.model,
-            ids: ids,
-            fields: fields
-        }, callback);
-    },
-    fetch_index: function (fields, callback) {
-        if (_.isEmpty(this.ids)) {
-            callback([]);
-        } else {
-            fields = fields || false;
-            this.fetch_ids([this.ids[this.index]], fields, function(records) {
-                callback(records[0]);
-            });
-        }
-    },
-    write: function (id, data, callback) {
-        this.rpc('/base/dataset/save', {
-            model: this.model,
-            id: id,
-            data: data,
-            context: this.context
-        }, callback);
-    },
-    call: function (method, ids, args, callback) {
-        ids = ids || [];
-        args = args || [];
-        this.rpc('/base/dataset/call', {
-            model: this.model,
-            method: method,
-            ids: ids,
-            args: args
-        }, callback);
-    },
-    unlink: function() {
-    }
-});
-
-openerp.base.DataSetSearch =  openerp.base.DataSet.extend( /** @lends openerp.base.DataSet# */{
-});
-
-openerp.base.DataSetRelational =  openerp.base.DataSet.extend( /** @lends openerp.base.DataSet# */{
 });
 
 };
diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js
index 9760c278699..691405ef5ec 100644
--- a/addons/base/static/src/js/form.js
+++ b/addons/base/static/src/js/form.js
@@ -56,6 +56,13 @@ openerp.base.FormView =  openerp.base.Controller.extend( /** @lends openerp.base
             this.view_manager.sidebar.load_multi_actions();
         }
     },
+    do_show: function () {
+        this.dataset.read_index(this.fields_view.fields, this.on_record_loaded);
+        this.$element.show();
+    },
+    do_hide: function () {
+        this.$element.hide();
+    },
     on_record_loaded: function(record) {
         if (record) {
             this.datarecord = record;
@@ -79,6 +86,30 @@ openerp.base.FormView =  openerp.base.Controller.extend( /** @lends openerp.base
             this.do_onchange(widget);
         }
     },
+    on_pager_action: function(action) {
+        switch (action) {
+            case 'first':
+                this.dataset.index = 0;
+                break;
+            case 'previous':
+                this.dataset.previous();
+                break;
+            case 'next':
+                this.dataset.next();
+                break;
+            case 'last':
+                this.dataset.index = this.dataset.ids.length - 1;
+                break;
+        }
+        this.dataset.read_index(this.fields_view.fields, this.on_record_loaded);
+    },
+    do_update_pager: function() {
+        var $pager = this.$element.find('div.oe_form_pager');
+        $pager.find("button[data-pager-action='first'], button[data-pager-action='previous']").attr('disabled', this.dataset.index == 0);
+        $pager.find("button[data-pager-action='next'], button[data-pager-action='last']").attr('disabled', this.dataset.index == this.dataset.ids.length - 1);
+        this.$element.find('span.oe_pager_index').html(this.dataset.index + 1);
+        this.$element.find('span.oe_pager_count').html(this.dataset.count);
+    },
     do_onchange: function(widget) {
         var self = this;
         this.ready = false;
@@ -159,37 +190,6 @@ openerp.base.FormView =  openerp.base.Controller.extend( /** @lends openerp.base
             this.switch_readonly();
         }
     },
-    do_show: function () {
-        this.dataset.fetch_index(this.fields_view.fields, this.on_record_loaded);
-        this.$element.show();
-    },
-    do_hide: function () {
-        this.$element.hide();
-    },
-    do_update_pager: function() {
-        var $pager = this.$element.find('div.oe_form_pager');
-        $pager.find("button[data-pager-action='first'], button[data-pager-action='previous']").attr('disabled', this.dataset.index == 0);
-        $pager.find("button[data-pager-action='next'], button[data-pager-action='last']").attr('disabled', this.dataset.index == this.dataset.ids.length - 1);
-        this.$element.find('span.oe_pager_index').html(this.dataset.index + 1);
-        this.$element.find('span.oe_pager_count').html(this.dataset.count);
-    },
-    on_pager_action: function(action) {
-        switch (action) {
-            case 'first':
-                this.dataset.index = 0;
-                break;
-            case 'previous':
-                this.dataset.previous();
-                break;
-            case 'next':
-                this.dataset.next();
-                break;
-            case 'last':
-                this.dataset.index = this.dataset.ids.length - 1;
-                break;
-        }
-        this.dataset.fetch_index(this.fields_view.fields, this.on_record_loaded);
-    },
     switch_readonly: function() {
     },
     switch_editable: function() {
@@ -676,32 +676,43 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
 });
 
 openerp.base.form.FieldOne2ManyDatasSet = openerp.base.DataSet.extend({
-// Extends view manager
+    start: function() {
+    },
+    write: function (id, data, callback) {
+        this._super(id, data, callback);
+    },
+    write: function (id, data, callback) {
+        this._super(id, data, callback);
+    },
+    unlink: function() {
+    }
 });
 
 openerp.base.form.FieldOne2ManyViewManager = openerp.base.ViewManager.extend({
-// Extends view manager
+    init: function(session, element_id, dataset, views) {
+        this._super(session, element_id, dataset, views);
+    },
 });
 
 openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({
     init: function(view, node) {
         this._super(view, node);
         this.template = "FieldOne2Many";
-        this.viewmanager = null;
         this.operations = [];
-
     },
     start: function() {
         this._super.apply(this, arguments);
         this.log("o2m.start");
-        var action = { res_model: this.field.relation, views: [ [false,"list"], ], };
-        this.viewmanager = new openerp.base.ViewManagerAction(this.view.session, this.element_id, action);
+        var views = [ [false,"list"], ];
+        this.dataset = new openerp.base.form.FieldOne2ManyDatasSet(this.session, this.field.relation);
+        this.viewmanager = new openerp.base.form.FieldOne2ManyViewManager(this.view.session, this.element_id, this.dataset, views);
+        this.viewmanager.start();
     },
     set_value: function(value) {
         this.value = value;
         this.log("o2m.set_value",value);
         this.viewmanager.dataset.ids = value;
-        // this.viewmanager.views.list.controller.do_update();
+        this.viewmanager.views.list.controller.do_update();
     },
     get_value: function(value) {
         return this.operations;
diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js
index 273f71ed82d..4b75168ae23 100644
--- a/addons/base/static/src/js/list.js
+++ b/addons/base/static/src/js/list.js
@@ -93,12 +93,12 @@ openerp.base.ListView = openerp.base.Controller.extend({
             // TODO: handle non-empty results.group_by with read_group
             self.dataset.context = results.context;
             self.dataset.domain = results.domain;
-            self.dataset.fetch(self.dataset.fields, 0, self.limit, self.do_fill_table);
+            self.dataset.read_slice(self.dataset.fields, 0, self.limit, self.do_fill_table);
         });
     },
     do_update: function () {
         var self = this;
-        self.dataset.fetch(self.dataset.fields, 0, self.limit, self.do_fill_table);
+        self.dataset.read(self.dataset.ids, self.dataset.fields, self.do_fill_table);
     }
 });
 
diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js
index f30e6f9c43f..fff4224274a 100644
--- a/addons/base/static/src/js/views.js
+++ b/addons/base/static/src/js/views.js
@@ -32,15 +32,14 @@ openerp.base.ActionManager = openerp.base.Controller.extend({
 openerp.base.views = new openerp.base.Registry();
 
 openerp.base.ViewManager =  openerp.base.Controller.extend({
-    init: function(session, element_id, model, views) {
+    init: function(session, element_id, dataset, views) {
         this._super(session, element_id);
-        this.model = model;
-        this.dataset = new openerp.base.DataSet(this.session, model);
+        this.model = dataset.model;
+        this.dataset = dataset;
         this.searchview = null;
         this.active_view = null;
         this.views_src = views;
         this.views = {};
-
     },
     /**
      * @returns {jQuery.Deferred} initial view loading promise
@@ -102,6 +101,23 @@ openerp.base.ViewManager =  openerp.base.Controller.extend({
         }
         return view_promise;
     },
+    /**
+     * Sets up the current viewmanager's search view.
+     *
+     * @param view_id the view to use or false for a default one
+     * @returns {jQuery.Deferred} search view startup deferred
+     */
+    setup_search_view: function(view_id, search_defaults) {
+        var self = this;
+        if (this.searchview) {
+            this.searchview.stop();
+        }
+        this.searchview = new openerp.base.SearchView(this, this.session, this.element_id + "_search", this.dataset, view_id, search_defaults);
+        this.searchview.on_search.add(function() {
+            self.views[self.active_view].controller.do_search.apply(self, arguments);
+        });
+        return this.searchview.start();
+    },
     /**
      * Called when one of the view want to execute an action
      */
@@ -117,7 +133,8 @@ openerp.base.ViewManager =  openerp.base.Controller.extend({
 
 openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({
     init: function(session, element_id, action, sidebar) {
-        this._super(session, element_id, action.res_model, action.views);
+        var dataset = new openerp.base.DataSetSearch(session, action.res_model);
+        this._super(session, element_id, dataset, action.views);
         this.action = action;
         this.sidebar = sidebar;
         if (sidebar)
@@ -126,12 +143,25 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({
     start: function() {
         var self = this;
         var inital_view_loaded = this._super();
+
+        // init sidebar
         if (this.sidebar) {
             this.$element.find('.view-manager-main-sidebar').html(this.sidebar.render());
             this.sidebar.start();
         }
-        var searchview_loaded = this.setup_search_view(this.action);
 
+        // init search view
+        var view_id = this.action.search_view_id ? this.action.search_view_id[0] || false : false;
+        var search_defaults = {};
+        _.each(this.action.context, function (value, key) {
+            var match = /^search_default_(.*)$/.exec(key);
+            if (match) {
+                search_defaults[match[1]] = value;
+            }
+        });
+        var searchview_loaded = this.setup_search_view(view_id,search_defaults);
+
+        // schedule auto_search
         if (this.action['auto_search']) {
             $.when(searchview_loaded, inital_view_loaded)
                 .then(this.searchview.do_search);
@@ -144,42 +174,6 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({
         }
         this._super();
     },
-    /**
-     * Sets up the current viewmanager's search view.
-     *
-     * @param action the action being executed
-     * @returns {jQuery.Deferred} search view startup deferred
-     */
-    setup_search_view:function (action) {
-        var self = this;
-        if (this.searchview) {
-            this.searchview.stop();
-        }
-        var view_id = action.search_view_id ? action.search_view_id[0] || false : false;
-
-        this.searchview = new openerp.base.SearchView(this, this.session, this.element_id + "_search", this.dataset, view_id, this.search_defaults());
-        this.searchview.on_search.add(function() {
-            self.views[self.active_view].controller.do_search.apply(self, arguments);
-        });
-        return this.searchview.start();
-    },
-    /**
-     * Extract search view defaults from the current action's context.
-     *
-     * These defaults are of the form {search_default_*: value}
-     *
-     * @returns {Object} a clean defaults mapping of {field_name: value}
-     */
-    search_defaults: function () {
-        var defaults = {};
-        _.each(this.action.context, function (value, key) {
-            var match = /^search_default_(.*)$/.exec(key);
-            if (match) {
-                defaults[match[1]] = value;
-            }
-        });
-        return defaults;
-    },
 });
 
 openerp.base.BaseWidget = openerp.base.Controller.extend({