From 3b4e3bdac63578d0c7a85cb90b3eb165351e1432 Mon Sep 17 00:00:00 2001 From: "odo@tinyerp.com" <> Date: Thu, 12 May 2011 12:00:38 +0200 Subject: [PATCH 1/9] [FIX] solve cache problem when unlink ir.model.data bzr revid: tfr@openerp.com-20110512100038-hng80ug44afq8fr7 --- openerp/addons/base/ir/ir_model.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index 0c3cd46356f..93ce7219c07 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -629,6 +629,13 @@ class ir_model_data(osv.osv): except: id = False return id + + def unlink(self, cr, uid, ids, context=None): + ref_ids = self.browse(cr, uid, ids, context=context) + for ref_id in ref_ids: + self._get_id.clear_cache(cr.dbname, uid, ref_id.module, ref_id.name) + self.get_object_reference.clear_cache(cr.dbname, uid, ref_id.module, ref_id.name) + super(ir_model_data,self).unlink(cr, uid, ids, context=context) def _update(self,cr, uid, model, module, values, xml_id=False, store=True, noupdate=False, mode='init', res_id=False, context=None): model_obj = self.pool.get(model) From 82b215c5831596b4de133f6d000094e08ae29e0c Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 20 May 2011 10:48:28 +0200 Subject: [PATCH 2/9] [FIX] ir.model.data: add missing return statement, would cause marshalling errors in XMLRPC bzr revid: odo@openerp.com-20110520084828-fre96mfaocmynmtb --- openerp/addons/base/ir/ir_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index 93ce7219c07..45e5a138c73 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -629,13 +629,13 @@ class ir_model_data(osv.osv): except: id = False return id - + def unlink(self, cr, uid, ids, context=None): ref_ids = self.browse(cr, uid, ids, context=context) for ref_id in ref_ids: self._get_id.clear_cache(cr.dbname, uid, ref_id.module, ref_id.name) self.get_object_reference.clear_cache(cr.dbname, uid, ref_id.module, ref_id.name) - super(ir_model_data,self).unlink(cr, uid, ids, context=context) + return super(ir_model_data,self).unlink(cr, uid, ids, context=context) def _update(self,cr, uid, model, module, values, xml_id=False, store=True, noupdate=False, mode='init', res_id=False, context=None): model_obj = self.pool.get(model) From 107bd89aea98c29c17292ad120458e8f3f03b083 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 31 May 2011 11:21:33 +0200 Subject: [PATCH 3/9] [IMP] convert: remove now useless call to ir.model.data._unlink for unlinked records. bzr revid: odo@openerp.com-20110531092133-rbobo5g4rmk1o8j7 --- openerp/tools/convert.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openerp/tools/convert.py b/openerp/tools/convert.py index 5536f311eb8..dd3a3d4a285 100644 --- a/openerp/tools/convert.py +++ b/openerp/tools/convert.py @@ -301,13 +301,11 @@ form: module.record_id""" % (xml_id,) pass if ids: self.pool.get(d_model).unlink(cr, self.uid, ids) - self.pool.get('ir.model.data')._unlink(cr, self.uid, d_model, ids) def _remove_ir_values(self, cr, name, value, model): ir_value_ids = self.pool.get('ir.values').search(cr, self.uid, [('name','=',name),('value','=',value),('model','=',model)]) if ir_value_ids: self.pool.get('ir.values').unlink(cr, self.uid, ir_value_ids) - self.pool.get('ir.model.data')._unlink(cr, self.uid, 'ir.values', ir_value_ids) return True From f6f4618fb069d4b35d48bc79ef556ea4ebedf46a Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 31 May 2011 11:22:32 +0200 Subject: [PATCH 4/9] [IMP] orm: minor typo and improvement in handling of ir.model.data during unlink() bzr revid: odo@openerp.com-20110531092232-pyt85iw2q7bf6qp1 --- openerp/osv/orm.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 2edb0f8c824..1d9cbe36ee8 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -3237,9 +3237,10 @@ class orm(orm_template): # Removing the ir_model_data reference if the record being deleted is a record created by xml/csv file, # as these are not connected with real database foreign keys, and would be dangling references. # Step 1. Calling unlink of ir_model_data only for the affected IDS. - referenced_ids = pool_model_data.search(cr, uid, [('res_id','in',list(sub_ids)),('model','=',self._name)], context=context) + reference_ids = pool_model_data.search(cr, uid, [('res_id','in',list(sub_ids)),('model','=',self._name)], context=context) # Step 2. Marching towards the real deletion of referenced records - pool_model_data.unlink(cr, uid, referenced_ids, context=context) + if reference_ids: + pool_model_data.unlink(cr, uid, reference_ids, context=context) # For the same reason, removing the record relevant to ir_values ir_value_ids = pool_ir_values.search(cr, uid, From b96c79147f21c7eea5f593b67fceb60e0e970d40 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 31 May 2011 11:24:26 +0200 Subject: [PATCH 5/9] [IMP] ir.model.data: remove obsolete _unlink() and unlink_mark, and their references Now all deletions in ir.model.data are automatically handled by ORM during the regular call to orm.unlink(). No need for any manual care. bzr revid: odo@openerp.com-20110531092426-ehvzf3dw6urqsdov --- openerp/addons/base/ir/ir_model.py | 42 +++++++++--------------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index 45e5a138c73..772163b9717 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -581,7 +581,6 @@ class ir_model_data(osv.osv): def __init__(self, pool, cr): osv.osv.__init__(self, pool, cr) self.doinit = True - self.unlink_mark = {} # also stored in pool to avoid being discarded along with this osv instance if getattr(pool, 'model_data_reference_ids', None) is None: @@ -727,11 +726,12 @@ class ir_model_data(osv.osv): table.replace('.', '_'))] = (table, inherit_id) return res_id - def _unlink(self, cr, uid, model, res_ids): - for res_id in res_ids: - self.unlink_mark[(model, res_id)] = False - cr.execute('delete from ir_model_data where res_id=%s and model=%s', (res_id, model)) - return True + def unlink(self, cr, uid, ids, context=None): + ref_ids = self.browse(cr, uid, ids, context=context) + for ref_id in ref_ids: + self._get_id.clear_cache(cr.dbname, uid, ref_id.module, ref_id.name) + self.get_object_reference.clear_cache(cr.dbname, uid, ref_id.module, ref_id.name) + super(ir_model_data,self).unlink(cr, uid, ids, context=context) def ir_set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=None, xml_id=False): if type(models[0])==type([]) or type(models[0])==type(()): @@ -765,9 +765,10 @@ class ir_model_data(osv.osv): module_in = ",".join(["%s"] * len(modules)) cr.execute('select id,name,model,res_id,module from ir_model_data where module IN (' + module_in + ') and noupdate=%s', modules + [False]) wkf_todo = [] + to_unlink = [] for (id, name, model, res_id,module) in cr.fetchall(): if (module,name) not in self.loads: - self.unlink_mark[(model,res_id)] = id + to_unlink.append((model,res_id)) if model=='workflow.activity': cr.execute('select res_type,res_id from wkf_instance where id IN (select inst_id from wkf_workitem where act_id=%s)', (res_id,)) wkf_todo.extend(cr.fetchall()) @@ -780,36 +781,19 @@ class ir_model_data(osv.osv): cr.commit() if not config.get('import_partial'): - for (model, res_id) in self.unlink_mark.keys(): + for (model, res_id) in to_unlink: if self.pool.get(model): self.__logger.info('Deleting %s@%s', res_id, model) try: self.pool.get(model).unlink(cr, uid, [res_id]) - if id: - ids = self.search(cr, uid, [('res_id','=',res_id), - ('model','=',model)]) - self.__logger.debug('=> Deleting %s: %s', - self._name, ids) - if len(ids) > 1 and \ - self.__logger.isEnabledFor(logging.WARNING): - self.__logger.warn( - 'Got %d %s for (%s, %d): %s', - len(ids), self._name, model, res_id, - map(itemgetter('module','name'), - self.read(cr, uid, ids, - ['name', 'module']))) - self.unlink(cr, uid, ids) - cr.execute( - 'DELETE FROM ir_values WHERE value=%s', - ('%s,%s'%(model, res_id),)) cr.commit() except Exception: cr.rollback() self.__logger.warn( - 'Could not delete id: %d of model %s\nThere ' - 'should be some relation that points to this ' - 'resource\nYou should manually fix this and ' - 'restart with --update=module', res_id, model) + 'Could not delete obsolete record with id: %d of model %s\n' + 'There should be some relation that points to this resource\n' + 'You should manually fix this and restart with --update=module', + res_id, model) return True ir_model_data() From 94761577b4a90645812ea4022068319a5f500314 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 22 Jun 2011 14:25:42 +0200 Subject: [PATCH 6/9] [IMP] Improved fields focus bzr revid: fme@openerp.com-20110622122542-ji3zt1fy9hc3qwgk --- addons/base/static/src/js/form.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index d221872598d..4aa52266e5b 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -252,18 +252,23 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV if (!this.ready) { return false; } - var invalid = false; - var values = {}; + var invalid = false, + values = {}, + first_invalid_field = null; for (var f in this.fields) { f = this.fields[f]; if (f.invalid) { invalid = true; f.update_dom(); + if (!first_invalid_field) { + first_invalid_field = f; + } } else if (f.touched) { values[f.name] = f.get_value(); } } if (invalid) { + first_invalid_field.focus(); this.on_invalid(); return false; } else { @@ -553,7 +558,7 @@ openerp.base.form.WidgetFrame = openerp.base.form.Widget.extend({ var widget_type = node.attrs.widget || type.type || node.tag; var widget = new (this.view.registry.get_object(widget_type)) (this.view, node); if (node.tag == 'field') { - if (node.attrs.default_focus == '1') { + if (!this.view.default_focus_field || node.attrs.default_focus == '1') { this.view.default_focus_field = widget; } if (node.attrs.nolabel != '1') { From 19aa4e05c266e6f089b34c4239f54c7ed1ab165e Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 22 Jun 2011 15:43:20 +0200 Subject: [PATCH 7/9] [IMP] In ViewManager, do not instanciate search view when action.search_view == false bzr revid: fme@openerp.com-20110622134320-ejkh13tbyhsd7wce --- addons/base/static/src/js/views.js | 32 +++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index ce2ee2c72e6..8b87d9cbdbe 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -113,7 +113,8 @@ openerp.base.ViewManager = openerp.base.Controller.extend({ * @returns {jQuery.Deferred} new view loading promise */ on_mode_switch: function(view_type) { - var view_promise; + var self = this, + view_promise; this.active_view = view_type; var view = this.views[view_type]; if (!view.controller) { @@ -124,6 +125,16 @@ openerp.base.ViewManager = openerp.base.Controller.extend({ if (view.embedded_view) { controller.set_embedded_view(view.embedded_view); } + if (view_type === 'list' && this.flags.search_view === false && this.action && this.action['auto_search']) { + // In case the search view is not instanciated: manually call ListView#search + controller.on_loaded.add({ + callback: function () { + controller.do_search([self.action.domain], [self.action.context], []); + }, + position: 'last', + unique: true + }); + } view_promise = controller.start(); var self = this; $.when(view_promise).then(function() { @@ -132,6 +143,7 @@ openerp.base.ViewManager = openerp.base.Controller.extend({ this.views[view_type].controller = controller; } + if (this.searchview) { if (view.controller.searchable === false) { this.searchview.hide(); @@ -261,16 +273,18 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({ } }); - // init search view - var searchview_id = this.action.search_view_id && this.action.search_view_id[0]; + if (this.flags.search_view !== false) { + // init search view + var searchview_id = this.action.search_view_id && this.action.search_view_id[0]; - var searchview_loaded = this.setup_search_view( - searchview_id || false, search_defaults); + var searchview_loaded = this.setup_search_view( + searchview_id || false, search_defaults); - // schedule auto_search - if (searchview_loaded != null && this.action['auto_search']) { - $.when(searchview_loaded, inital_view_loaded) - .then(this.searchview.do_search); + // schedule auto_search + if (searchview_loaded != null && this.action['auto_search']) { + $.when(searchview_loaded, inital_view_loaded) + .then(this.searchview.do_search); + } } }, stop: function() { From 2cbb2fe36c778a1660ecf10a63a6e0c940736642 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 22 Jun 2011 16:38:05 +0200 Subject: [PATCH 8/9] [IMP] QWeb2 t-js now handles more than one child bzr revid: fme@openerp.com-20110622143805-qryluomj7w4l3s5m --- addons/base/static/lib/qweb/qweb2.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/addons/base/static/lib/qweb/qweb2.js b/addons/base/static/lib/qweb/qweb2.js index 5e53ddbf645..e617df60183 100644 --- a/addons/base/static/lib/qweb/qweb2.js +++ b/addons/base/static/lib/qweb/qweb2.js @@ -670,15 +670,10 @@ QWeb2.Element = (function() { this.top("(function(" + value + ") {"); this.bottom("})(dict);"); this.indent(); - if (this.children.length === 1) { - var lines = this.children[0].node.data.split(/\r?\n/); - for (var i = 0, ilen = lines.length; i < ilen; i++) { - this.top(lines[i]); - } - } else { - this.engine.tools.exception("'js' code block contains " + this.children.length + " nodes instead of 1"); + var lines = this.engine.tools.xml_node_to_string(this.node, true).split(/\r?\n/); + for (var i = 0, ilen = lines.length; i < ilen; i++) { + this.top(lines[i]); } - // Maybe I could handle the children ? this.process_children = false; }, compile_action_debug : function(value) { From 58291d4ab605ff5b9882bb84de537ce1ff6e73cf Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Wed, 22 Jun 2011 16:49:16 +0200 Subject: [PATCH 9/9] [imp] added unlink to dataset and list_view (currently just reloads the whole list) bzr revid: nicolas.vanhoren@openerp.com-20110622144916-cst2ad1s0gtchlxi --- addons/base/static/src/js/data.js | 21 ++++++++++++++++++--- addons/base/static/src/js/list.js | 20 +------------------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js index 736c31c1f7b..47e6d4fed3d 100644 --- a/addons/base/static/src/js/data.js +++ b/addons/base/static/src/js/data.js @@ -310,9 +310,10 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base. context: this.context }, callback); }, - unlink: function(ids) { - // to implement in children - this.notification.notify("Unlink", ids); + unlink: function(ids, callback, error_callback) { + var self = this; + return this.call_and_eval("unlink", [ids, this.context], null, 1, + callback, error_callback); }, call: function (method, args, callback, error_callback) { return this.rpc('/base/dataset/call', { @@ -362,9 +363,12 @@ openerp.base.DataSetStatic = openerp.base.DataSet.extend({ set_ids: function (ids) { this.ids = ids; this.count = this.ids.length; + this.index = this.index <= this.count - 1 ? + this.index : (this.count > 0 ? this.count - 1 : 0); }, unlink: function(ids) { this.on_unlink(ids); + return $.Deferred().resolve({result: true}); }, on_unlink: function(ids) { this.set_ids(_.without.apply(null, [this.ids].concat(ids))); @@ -438,6 +442,17 @@ openerp.base.DataSetSearch = openerp.base.DataSet.extend({ this._sort.unshift((reverse ? '-' : '') + field); return undefined; + }, + unlink: function(ids, callback, error_callback) { + var self = this; + return this._super(ids, function(result) { + self.ids = _.without.apply(_, [self.ids].concat(ids)); + self.count = self.ids.length; + self.index = self.index <= self.count - 1 ? + self.index : (self.count > 0 ? self.count -1 : 0); + if (callback) + callback(result); + }, error_callback); } }); diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index bd2518dcb66..38162849e08 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -336,25 +336,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi } var self = this; return $.when(this.dataset.unlink(ids)).then(function () { - _(self.rows).chain() - .map(function (row, index) { - return { - index: index, - id: row.data.id.value - };}) - .filter(function (record) { - return _.contains(ids, record.id); - }) - .sort(function (a, b) { - // sort in reverse index order, so we delete from the end - // and don't blow up the following indexes (leading to - // removing the wrong records from the visible list) - return b.index - a.index; - }) - .each(function (record) { - self.rows.splice(record.index, 1); - }); - // TODO only refresh modified rows + self.reload_content(); }); }, /**