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({