From 71b057aa3402346ccfc4364d20a81a96b5e632f8 Mon Sep 17 00:00:00 2001 From: "Vidhin Mehta (OpenERP)" Date: Fri, 19 Aug 2011 16:03:22 +0530 Subject: [PATCH 01/34] [FIX]Fix add remove shortcut problem on switch view and update session. bzr revid: vme@tinyerp.com-20110819103322-7cph3n3ey7z39gkj --- addons/base/static/src/js/chrome.js | 16 ++++++++++++---- addons/base/static/src/js/views.js | 1 + 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js index 3aff7b5e402..ec666cf8c8a 100644 --- a/addons/base/static/src/js/chrome.js +++ b/addons/base/static/src/js/chrome.js @@ -584,13 +584,17 @@ openerp.base.Header = openerp.base.Widget.extend({ sc.binding = {}; $(sc.binding).bind({ 'add': function (e, attrs) { - var $shortcut = $('
  • ', { - 'data-id': attrs.res_id + shortcuts_ds.create(attrs, function (out) { + var $shortcut = $('
  • ', { + 'data-shortcut-id':out.result, + 'data-id': attrs.res_id }).text(attrs.name) .appendTo(self.$element.find('.oe-shortcuts ul')); - shortcuts_ds.create(attrs, function (out) { - $shortcut.data('shortcut-id', out.result); + attrs.id = out.result; + sc.splice(sc.lenght,0,attrs); + sc.push.apply(sc); }); + }, 'remove-current': function () { var menu_id = self.session.active_id; @@ -599,6 +603,9 @@ openerp.base.Header = openerp.base.Widget.extend({ var shortcut_id = $shortcut.data('shortcut-id'); $shortcut.remove(); shortcuts_ds.unlink([shortcut_id]); + sc1 = _.reject(sc, function(shortcut){ return shortcut_id === shortcut.id}); + sc.splice(0, sc.length); + sc.push.apply(sc ,sc1); } }); } @@ -609,6 +616,7 @@ openerp.base.Header = openerp.base.Widget.extend({ self.$element.find('.oe-shortcuts') .html(QWeb.render('Shortcuts', {'shortcuts': shortcuts})) .undelegate('li', 'click') + .delegate('li', 'click', function(e) { e.stopPropagation(); var id = $(this).data('id'); diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index ad75268156f..7a15f9a37ad 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -342,6 +342,7 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({ shortcut_add_remove: function() { var self = this; var $shortcut_toggle = this.$element.find('.oe-shortcut-toggle'); + $shortcut_toggle.unbind("click").click(); $shortcut_toggle.click(function() { if ($shortcut_toggle.hasClass("oe-shortcut-remove")) { $(self.session.shortcuts.binding).trigger('remove-current'); From a97bb0476ca74b2fa43bc58d408b68d78477610e Mon Sep 17 00:00:00 2001 From: "Vidhin Mehta (OpenERP)" Date: Tue, 23 Aug 2011 14:31:21 +0530 Subject: [PATCH 02/34] [fix]Optimize code in add event bzr revid: vme@tinyerp.com-20110823090121-gk2iayz1eavjwdfg --- addons/base/static/src/js/chrome.js | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js index ec666cf8c8a..ef8779152bc 100644 --- a/addons/base/static/src/js/chrome.js +++ b/addons/base/static/src/js/chrome.js @@ -585,28 +585,26 @@ openerp.base.Header = openerp.base.Widget.extend({ $(sc.binding).bind({ 'add': function (e, attrs) { shortcuts_ds.create(attrs, function (out) { - var $shortcut = $('
  • ', { - 'data-shortcut-id':out.result, - 'data-id': attrs.res_id + $('
  • ', { + 'data-shortcut-id':out.result, + 'data-id': attrs.res_id }).text(attrs.name) .appendTo(self.$element.find('.oe-shortcuts ul')); attrs.id = out.result; - sc.splice(sc.lenght,0,attrs); - sc.push.apply(sc); + sc.push(attrs); }); - - }, + }, 'remove-current': function () { var menu_id = self.session.active_id; var $shortcut = self.$element - .find('.oe-shortcuts li[data-id=' + menu_id + ']'); + .find('.oe-shortcuts li[data-id=' + menu_id + ']'); var shortcut_id = $shortcut.data('shortcut-id'); $shortcut.remove(); shortcuts_ds.unlink([shortcut_id]); - sc1 = _.reject(sc, function(shortcut){ return shortcut_id === shortcut.id}); + var sc_new = _.reject(sc, function(shortcut){ return shortcut_id === shortcut.id}); sc.splice(0, sc.length); - sc.push.apply(sc ,sc1); - } + sc.push.apply(sc,sc_new); + } }); } return this.rpc('/base/session/sc_list', {}, function(shortcuts) { From 180ffb18a14715f1af17bfa2f94213d457e6a861 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Tue, 23 Aug 2011 12:33:43 +0200 Subject: [PATCH 03/34] [REF] openerp-server: streamlining startup script. bzr revid: vmt@openerp.com-20110823103343-rvy2zkre8bo9cq6g --- openerp-server | 269 ++++++++++++++++++++----------------- openerp/tools/translate.py | 3 +- 2 files changed, 144 insertions(+), 128 deletions(-) diff --git a/openerp-server b/openerp-server index 00da3ac640a..9c9a8c2bde7 100755 --- a/openerp-server +++ b/openerp-server @@ -30,9 +30,6 @@ GNU Public Licence. (c) 2003-TODAY, Fabien Pinckaers - OpenERP s.a. """ -#---------------------------------------------------------- -# python imports -#---------------------------------------------------------- import logging import os import signal @@ -45,139 +42,128 @@ import openerp __author__ = openerp.release.author __version__ = openerp.release.version -if os.name == 'posix': - import pwd - # We DON't log this using the standard logger, because we might mess - # with the logfile's permissions. Just do a quick exit here. - if pwd.getpwuid(os.getuid())[0] == 'root' : - sys.stderr.write("Attempted to run OpenERP server as root. This is not good, aborting.\n") +def check_root_user(): + """ Exit if the process’s user is 'root' (on POSIX system).""" + if os.name == 'posix': + import pwd + if pwd.getpwuid(os.getuid())[0] == 'root' : + sys.stderr.write("Running as user 'root' is a security risk, aborting.\n") + sys.exit(1) + +def check_postgres_user(): + """ Exit if the configured database user is 'postgres'.""" + config = openerp.tools.config + logger = logging.getLogger('server') + if config['db_user'] == 'postgres': + sys.stderr.write("Using the database user 'postgres' is a security risk, aborting.") sys.exit(1) -#----------------------------------------------------------------------- -# parse the command line -#----------------------------------------------------------------------- -openerp.tools.config.parse_config(sys.argv[1:]) -config = openerp.tools.config +def report_configuration(): + """ Log the server version and some configuration values.""" + config = openerp.tools.config + logger = logging.getLogger('server') + logger.info("OpenERP version %s", __version__) + for name, value in [('addons paths', config['addons_path']), + ('database hostname', config['db_host'] or 'localhost'), + ('database port', config['db_port'] or '5432'), + ('database user', config['db_user'])]: + logger.info("%s: %s", name, value) -#---------------------------------------------------------- -# get logger -#---------------------------------------------------------- -openerp.netsvc.init_logger() -logger = logging.getLogger('server') +# TODO is a \n better? +def setup_pid_file(): + config = openerp.tools.config + if config['pidfile']: + fd = open(config['pidfile'], 'w') + pidtext = "%d" % (os.getpid()) + fd.write(pidtext) + fd.close() -logger.info("OpenERP version - %s", __version__) -for name, value in [('addons_path', config['addons_path']), - ('database hostname', config['db_host'] or 'localhost'), - ('database port', config['db_port'] or '5432'), - ('database user', config['db_user'])]: - logger.info("%s - %s", name, value) +def run_registry(dbname): + """ Preload a registry, possibly run a test file, and start the cron.""" + db, pool = openerp.pooler.get_db_and_pool(dbname, update_module=config['init'] or config['update'], pooljobs=False) -# Don't allow if the connection to PostgreSQL done by postgres user -if config['db_user'] == 'postgres': - logger.error("Connecting to the database as 'postgres' user is forbidden, as it present major security issues. Shutting down.") - sys.exit(1) + if config["test_file"]: + cr = db.cursor() + logger = logging.getLogger('server') + logger.info('loading test file %s', config["test_file"]) + openerp.tools.convert_yaml_import(cr, 'base', file(config["test_file"]), {}, 'test', True) + cr.rollback() + cr.close() -#---------------------------------------------------------- -# init net service -#---------------------------------------------------------- -logger.info('initialising distributed objects services') + pool.get('ir.cron').restart(db.dbname) -#---------------------------------------------------------- -# Load and update databases if requested -#---------------------------------------------------------- +def export_translation(): + config = openerp.tools.config + dbname = config['db_name'] + logger = logging.getLogger('server') -if not ( config["stop_after_init"] or \ - config["translate_in"] or \ - config["translate_out"] ): - openerp.osv.osv.start_object_proxy() - openerp.service.web_services.start_web_services() + if config["language"]: + msg = "language %s" % (config["language"],) + else: + msg = "new language" + logger.info('writing translation file for %s to %s', msg, + config["translate_out"]) + + fileformat = os.path.splitext(config["translate_out"])[-1][1:].lower() + buf = file(config["translate_out"], "w") + cr = openerp.pooler.get_db(dbname).cursor() + openerp.tools.trans_export(config["language"], + config["translate_modules"] or ["all"], buf, fileformat, cr) + cr.close() + buf.close() + + logger.info('translation file written successfully') + +def import_translation(): + config = openerp.tools.config + context = {'overwrite': config["overwrite_existing_translations"]} + dbname = config['db_name'] + + cr = openerp.pooler.get_db(dbname).cursor() + openerp.tools.trans_load( cr, config["translate_in"], config["language"], + context=context) + openerp.tools.trans_update_res_ids(cr) + cr.commit() + cr.close() + +def start_services(): http_server = openerp.service.http_server netrpc_server = openerp.service.netrpc_server + + # Instantiate local services (this is a legacy design). + openerp.osv.osv.start_object_proxy() + # Export (for RPC) services. + openerp.service.web_services.start_web_services() + + # Initialize the HTTP stack. http_server.init_servers() http_server.init_xmlrpc() http_server.init_static_http() netrpc_server.init_servers() -if config['db_name']: - for dbname in config['db_name'].split(','): - db, pool = openerp.pooler.get_db_and_pool(dbname, update_module=config['init'] or config['update'], pooljobs=False) - cr = db.cursor() + # Start the main cron thread. + openerp.netsvc.start_agent() - if config["test_file"]: - logger.info('loading test file %s', config["test_file"]) - openerp.tools.convert_yaml_import(cr, 'base', file(config["test_file"]), {}, 'test', True) - cr.rollback() - - pool.get('ir.cron').restart(db.dbname) - - cr.close() - -#---------------------------------------------------------- -# translation stuff -#---------------------------------------------------------- -if config["translate_out"]: - if config["language"]: - msg = "language %s" % (config["language"],) - else: - msg = "new language" - logger.info('writing translation file for %s to %s', msg, config["translate_out"]) - - fileformat = os.path.splitext(config["translate_out"])[-1][1:].lower() - buf = file(config["translate_out"], "w") - dbname = config['db_name'] - cr = openerp.pooler.get_db(dbname).cursor() - openerp.tools.trans_export(config["language"], config["translate_modules"] or ["all"], buf, fileformat, cr) - cr.close() - buf.close() - - logger.info('translation file written successfully') - sys.exit(0) - -if config["translate_in"]: - context = {'overwrite': config["overwrite_existing_translations"]} - dbname = config['db_name'] - cr = openerp.pooler.get_db(dbname).cursor() - openerp.tools.trans_load(cr, - config["translate_in"], - config["language"], - context=context) - openerp.tools.trans_update_res_ids(cr) - cr.commit() - cr.close() - sys.exit(0) - -#---------------------------------------------------------------------------------- -# if we don't want the server to continue to run after initialization, we quit here -#---------------------------------------------------------------------------------- -if config["stop_after_init"]: - sys.exit(0) - -openerp.netsvc.start_agent() - -#---------------------------------------------------------- -# Launch Servers -#---------------------------------------------------------- - -LST_SIGNALS = ['SIGINT', 'SIGTERM'] - -SIGNALS = dict( - [(getattr(signal, sign), sign) for sign in LST_SIGNALS] -) + # Start the top-level servers threads (normally HTTP, HTTPS, and NETRPC). + openerp.netsvc.Server.startAll() quit_signals_received = 0 -def handler(signum, frame): - """ - :param signum: the signal number +def signal_handler(sig, frame): + """ Signal handler: exit ungracefully on the second handled signal. + + :param sig: the signal number :param frame: the interrupted stack frame or None """ global quit_signals_received quit_signals_received += 1 if quit_signals_received > 1: + # logging.shutdown was already called at this point. sys.stderr.write("Forced shutdown.\n") os._exit(0) -def dumpstacks(signum, frame): +def dumpstacks(sig, frame): + """ Signal handler: dump a stack trace for each existing thread.""" # code from http://stackoverflow.com/questions/132058/getting-stack-trace-from-a-running-python-application#answer-2569696 # modified for python 2.5 compatibility thread_map = dict(threading._active, **threading._limbo) @@ -191,20 +177,32 @@ def dumpstacks(signum, frame): code.append(" %s" % (line.strip())) logging.getLogger('dumpstacks').info("\n".join(code)) -for signum in SIGNALS: - signal.signal(signum, handler) +def setup_signal_handlers(): + SIGNALS = map(lambda x: getattr(signal, "SIG%s" % x), "INT TERM".split()) + map(lambda sig: signal.signal(sig, signal_handler), SIGNALS) + if os.name == 'posix': + signal.signal(signal.SIGQUIT, dumpstacks) -if os.name == 'posix': - signal.signal(signal.SIGQUIT, dumpstacks) +def quit_on_signals(): + """ Wait for one or two signals then shutdown the server. + + The first SIGINT or SIGTERM signal will initiate a graceful shutdown while + a second one if any will force an immediate exit. + + """ + # Wait for a first signal to be handled. (time.sleep will be interrupted + # by the signal handler.) + while quit_signals_received == 0: + time.sleep(60) -def quit(): openerp.netsvc.Agent.quit() openerp.netsvc.Server.quitAll() + config = openerp.tools.config if config['pidfile']: os.unlink(config['pidfile']) - logger = logging.getLogger('shutdown') - logger.info("Initiating OpenERP Server shutdown") - logger.info("Hit CTRL-C again or send a second signal to immediately terminate the server...") + logger = logging.getLogger('server') + logger.info("Initiating shutdown") + logger.info("Hit CTRL-C again or send a second signal to force the sutdown.") logging.shutdown() # manually join() all threads before calling sys.exit() to allow a second signal @@ -219,19 +217,36 @@ def quit(): time.sleep(0.05) sys.exit(0) -if config['pidfile']: - fd = open(config['pidfile'], 'w') - pidtext = "%d" % (os.getpid()) - fd.write(pidtext) - fd.close() +if __name__ == "__main__": -openerp.netsvc.Server.startAll() + check_root_user() + openerp.tools.config.parse_config(sys.argv[1:]) + check_postgres_user() + openerp.netsvc.init_logger() + report_configuration() -logger.info('OpenERP server is running, waiting for connections...') + config = openerp.tools.config -while quit_signals_received == 0: - time.sleep(60) + if config["translate_out"]: + export_translation() + sys.exit(0) -quit() + if config["translate_in"]: + import_translation() + sys.exit(0) + + if config['db_name']: + for dbname in config['db_name'].split(','): + run_registry(dbname) + + if config["stop_after_init"]: + sys.exit(0) + + setup_pid_file() + setup_signal_handlers() + start_services() + logger = logging.getLogger('server') + logger.info('OpenERP server is running, waiting for connections...') + quit_on_signals() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/tools/translate.py b/openerp/tools/translate.py index 4b9adb144bd..277965c5449 100644 --- a/openerp/tools/translate.py +++ b/openerp/tools/translate.py @@ -458,7 +458,8 @@ def trans_export(lang, modules, buffer, format, cr): tar.close() else: - raise Exception(_('Bad file format')) + raise Exception(_('Unrecognized extension: must be one of ' + '.csv, .po, or .tgz (received .%s).' % format)) newlang = not bool(lang) if newlang: From 8de550dea8de6316b760f9a366cb59d060e053c3 Mon Sep 17 00:00:00 2001 From: "Amit Bhavsar (Open ERP)" Date: Wed, 24 Aug 2011 11:07:29 +0530 Subject: [PATCH 04/34] [usability],hide the partner categories in simple view bzr revid: amb@tinyerp.com-20110824053729-dkyk9e282azevs6q --- openerp/addons/base/res/partner/partner_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/res/partner/partner_view.xml b/openerp/addons/base/res/partner/partner_view.xml index 763147fb47e..8d56087fd6c 100644 --- a/openerp/addons/base/res/partner/partner_view.xml +++ b/openerp/addons/base/res/partner/partner_view.xml @@ -584,7 +584,7 @@ Manage the partner categories in order to better classify them for tracking and analysis purposes. A partner may belong to several categories and categories have a hierarchy structure: a partner belonging to a category also belong to his parent category. - + Date: Thu, 25 Aug 2011 10:18:33 +0200 Subject: [PATCH 05/34] [REV] xmo@openerp.com-20110824131606-yokgoe3dz9ltaz2l, has nothing to do with the issue and does not actually fix it (just fudges some timing so it happens slightly less often) bzr revid: xmo@openerp.com-20110825081833-a1vbcdm59mrzf2d0 --- addons/base/static/src/js/list.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 47c04537ddc..9797b5dff99 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -120,7 +120,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi */ start: function() { this.$element.addClass('oe-listview'); - return this.reload_view(); + return this.reload_view(null, null, true); }, /** * Called after loading the list view's description, sets up such things @@ -362,22 +362,22 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi * @param {Boolean} [grouped] Should the list be displayed grouped * @param {Object} [context] context to send the server while loading the view */ - reload_view: function (grouped, context) { - var self = this, d = $.Deferred(); - d.then(function (field_view_get) { + reload_view: function (grouped, context, initial) { + var self = this; + var callback = function (field_view_get) { + console.log('loaded', initial ? 'initial' : 'subsequent'); self.on_loaded(field_view_get, grouped); - }); + }; if (this.embedded_view) { - d.resolve({fields_view: this.embedded_view}); + return $.Deferred().then(callback).resolve({fields_view: this.embedded_view}); } else { - this.rpc('/base/listview/load', { + return this.rpc('/base/listview/load', { model: this.model, view_id: this.view_id, context: this.dataset.get_context(context), toolbar: this.options.sidebar - }, function () { d.resolve.apply(this, arguments); }); + }, callback); } - return d.promise(); }, /** * re-renders the content of the list view From d2da68ad8b66e2c93c4552cb47bde7a34378c635 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 25 Aug 2011 10:22:21 +0200 Subject: [PATCH 06/34] [FIX] actually fix race condition on listview init: incorrect on_mode_switch override in xmo@openerp.com-20110816123510-gcx0dk8b2sgox5oi did not propagate primise from ViewManager's on_mode_switch bzr revid: xmo@openerp.com-20110825082221-tasmo3je0wu4iw6h --- addons/base/static/src/js/views.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index c6782150297..7f6d78d9495 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -325,8 +325,9 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({ } }, on_mode_switch: function (view_type) { - this._super(view_type); - this.shortcut_check(this.views[view_type]); + return $.when( + this._super(view_type), + this.shortcut_check(this.views[view_type])); }, shortcut_check : function(view) { var self = this; From 6e7a9a1a3c7e00e7aa24fcfb37b22c815e0c257c Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 25 Aug 2011 11:42:12 +0200 Subject: [PATCH 07/34] [IMP] Form fields now uses niv's parse/format methods bzr revid: fme@openerp.com-20110825094212-31l90vq66riiabl4 --- addons/base/static/src/js/form.js | 94 ++++++------------------------- 1 file changed, 17 insertions(+), 77 deletions(-) diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 7a4d3c92d89..3280b7e0d81 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -949,7 +949,7 @@ openerp.base.form.FieldChar = openerp.base.form.Field.extend({ }, set_value: function(value) { this._super.apply(this, arguments); - var show_value = (value != null && value !== false) ? value : ''; + var show_value = openerp.base.format_value(value, this, ''); this.$element.find('input').val(show_value); }, update_dom: function() { @@ -957,16 +957,16 @@ openerp.base.form.FieldChar = openerp.base.form.Field.extend({ this.$element.find('input').attr('disabled', this.readonly); }, set_value_from_ui: function() { - this.value = this.$element.find('input').val(); + this.value = openerp.base.parse_value(this.$element.find('input').val(), this); this._super(); }, validate: function() { this.invalid = false; - var value = this.$element.find('input').val(); - if (value === "") { - this.invalid = this.required; - } else if (this.validation_regex) { - this.invalid = !this.validation_regex.test(value); + try { + var value = openerp.base.parse_value(this.$element.find('input').val(), this, ''); + this.invalid = this.required && value === ''; + } catch(e) { + this.invalid = true; } }, focus: function() { @@ -978,7 +978,6 @@ openerp.base.form.FieldEmail = openerp.base.form.FieldChar.extend({ init: function(view, node) { this._super(view, node); this.template = "FieldEmail"; - this.validation_regex = /@/; }, start: function() { this._super.apply(this, arguments); @@ -993,8 +992,7 @@ openerp.base.form.FieldEmail = openerp.base.form.FieldChar.extend({ }, set_value: function(value) { this._super.apply(this, arguments); - var show_value = (value != null && value !== false) ? value : ''; - this.$element.find('a').attr('href', 'mailto:' + show_value); + this.$element.find('a').attr('href', 'mailto:' + this.$element.find('input').val()); } }); @@ -1017,44 +1015,13 @@ openerp.base.form.FieldUrl = openerp.base.form.FieldChar.extend({ }); openerp.base.form.FieldFloat = openerp.base.form.FieldChar.extend({ - init: function(view, node) { - this._super(view, node); - this.validation_regex = /^-?\d+(\.\d+)?$/; - }, set_value: function(value) { - this._super.apply(this, [value]); if (value === false || value === undefined) { // As in GTK client, floats default to 0 value = 0; this.dirty = true; } - var show_value = value.toFixed(2); - this.$element.find('input').val(show_value); - }, - set_value_from_ui: function() { - this.value = Number(this.$element.find('input').val().replace(/,/g, '.')); - this._super(); - } -}); - -openerp.base.form.FieldInteger = openerp.base.form.FieldFloat.extend({ - init: function(view, node) { - this._super(view, node); - this.validation_regex = /^-?\d+$/; - }, - set_value: function(value) { this._super.apply(this, [value]); - if (value === false || value === undefined) { - // TODO fme: check if GTK client default integers to 0 (like it does with floats) - value = 0; - this.dirty = true; - } - var show_value = parseInt(value, 10); - this.$element.find('input').val(show_value); - }, - set_value_from_ui: function() { - this.value = Number(this.$element.find('input').val()); - this._super(); } }); @@ -1063,7 +1030,6 @@ openerp.base.form.FieldDatetime = openerp.base.form.Field.extend({ this._super(view, node); this.template = "FieldDate"; this.jqueryui_object = 'datetimepicker'; - this.validation_regex = /^\d+-\d+-\d+( \d+:\d+(:\d+)?)?$/; }, start: function() { this._super.apply(this, arguments); @@ -1103,8 +1069,6 @@ openerp.base.form.FieldDatetime = openerp.base.form.Field.extend({ var value = this.$element.find('input').val(); if (value === "") { this.invalid = this.required; - } else if (this.validation_regex) { - this.invalid = !this.validation_regex.test(value); } else { this.invalid = !this.$element.find('input')[this.jqueryui_object]('getDate'); } @@ -1120,39 +1084,15 @@ openerp.base.form.FieldDate = openerp.base.form.FieldDatetime.extend({ init: function(view, node) { this._super(view, node); this.jqueryui_object = 'datepicker'; - this.validation_regex = /^\d+-\d+-\d+$/; }, parse: openerp.base.str_to_date, format: openerp.base.date_to_str }); -openerp.base.form.FieldFloatTime = openerp.base.form.FieldChar.extend({ - init: function(view, node) { - this._super(view, node); - this.validation_regex = /^\d+:\d+$/; - }, - set_value: function(value) { - this._super.apply(this, [value]); - if (value === false || value === undefined) { - // As in GTK client, floats default to 0 - value = 0; - this.dirty = true; - } - var show_value = _.sprintf("%02d:%02d", Math.floor(value), Math.round((value % 1) * 60)); - this.$element.find('input').val(show_value); - }, - set_value_from_ui: function() { - var time = this.$element.find('input').val().split(':'); - this.set_value(parseInt(time[0], 10) + parseInt(time[1], 10) / 60); - this._super(); - } -}); - openerp.base.form.FieldText = openerp.base.form.Field.extend({ init: function(view, node) { this._super(view, node); this.template = "FieldText"; - this.validation_regex = null; }, start: function() { this._super.apply(this, arguments); @@ -1160,7 +1100,7 @@ openerp.base.form.FieldText = openerp.base.form.Field.extend({ }, set_value: function(value) { this._super.apply(this, arguments); - var show_value = (value != null && value !== false) ? value : ''; + var show_value = openerp.base.format_value(value, this, ''); this.$element.find('textarea').val(show_value); }, update_dom: function() { @@ -1168,16 +1108,16 @@ openerp.base.form.FieldText = openerp.base.form.Field.extend({ this.$element.find('textarea').attr('disabled', this.readonly); }, set_value_from_ui: function() { - this.value = this.$element.find('textarea').val(); + this.value = openerp.base.parse_value(this.$element.find('textarea').val(), this); this._super(); }, validate: function() { this.invalid = false; - var value = this.$element.find('textarea').val(); - if (value === "") { - this.invalid = this.required; - } else if (this.validation_regex) { - this.invalid = !this.validation_regex.test(value); + try { + var value = openerp.base.parse_value(this.$element.find('textarea').val(), this, ''); + this.invalid = this.required && value === ''; + } catch(e) { + this.invalid = true; } }, focus: function() { @@ -2440,9 +2380,9 @@ openerp.base.form.widgets = new openerp.base.Registry({ 'reference' : 'openerp.base.form.FieldReference', 'boolean' : 'openerp.base.form.FieldBoolean', 'float' : 'openerp.base.form.FieldFloat', - 'integer': 'openerp.base.form.FieldInteger', + 'integer': 'openerp.base.form.FieldFloat', + 'float_time': 'openerp.base.form.FieldFloat', 'progressbar': 'openerp.base.form.FieldProgressBar', - 'float_time': 'openerp.base.form.FieldFloatTime', 'image': 'openerp.base.form.FieldBinaryImage', 'binary': 'openerp.base.form.FieldBinaryFile' }); From 3da1145220c86e8e2b52c883ce34078fa4fde2a6 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 25 Aug 2011 11:48:06 +0200 Subject: [PATCH 08/34] [IMP] Improved form's datetime widget so the content is always visible even when view size is shrinked down bzr revid: fme@openerp.com-20110825094806-hfiagqp54gf9rzha --- addons/base/static/src/css/base.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index cd420ea8c0d..46364c4fa1d 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -870,6 +870,9 @@ label.error { .openerp .oe_forms input[type="text"], .openerp .oe_forms input[type="password"], .openerp .oe_forms select, .openerp .oe_forms .button { height: 22px; } +.openerp .oe_forms input.field_datetime { + min-width: 11em; +} .openerp .oe_forms .button { color: #4c4c4c; white-space: nowrap; From 455928127fa2ed44a6f7fda14cab57052031c89f Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 25 Aug 2011 12:06:43 +0200 Subject: [PATCH 09/34] [FIX] safari/javascriptcore blows up on 'super' because it thinks it's a keyword bzr revid: xmo@openerp.com-20110825100643-k7nbcla8h38siozr --- addons/base/static/src/js/views.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index 7f6d78d9495..9e981e7c3e2 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -531,17 +531,17 @@ openerp.base.TranslateDialog = openerp.base.Dialog.extend({ }, open: function(field) { var self = this, - super = this._super; + sup = this._super; $.when(this.languages_loaded).then(function() { if (self.view.translatable_fields && self.view.translatable_fields.length) { self.do_load_fields_values(function() { - super.call(self); + sup.call(self); if (field) { // TODO: focus and scroll to field } }); } else { - super.call(self); + sup.call(self); } }); }, From 5864a23352e200eeab37b0b1e6b8c466e8261e5b Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 25 Aug 2011 12:27:56 +0200 Subject: [PATCH 10/34] [REM] leftover debugging code bzr revid: xmo@openerp.com-20110825102756-b3d8jf7yud0m98ol --- addons/base/static/src/js/list.js | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 9797b5dff99..e83454deebb 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -365,7 +365,6 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi reload_view: function (grouped, context, initial) { var self = this; var callback = function (field_view_get) { - console.log('loaded', initial ? 'initial' : 'subsequent'); self.on_loaded(field_view_get, grouped); }; if (this.embedded_view) { From 259892f837588c7b47c81cfe513d245e4526226f Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 25 Aug 2011 12:33:36 +0200 Subject: [PATCH 11/34] [FIX] selector for config overview widget: widget root has moved, .oe-dashboard-config-overview is now on this. so don't include it bzr revid: xmo@openerp.com-20110825103336-nwyybou1hghaudud --- addons/base_dashboard/static/src/js/dashboard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/base_dashboard/static/src/js/dashboard.js b/addons/base_dashboard/static/src/js/dashboard.js index 8cf94a43362..e5b06a13461 100644 --- a/addons/base_dashboard/static/src/js/dashboard.js +++ b/addons/base_dashboard/static/src/js/dashboard.js @@ -321,7 +321,7 @@ openerp.base_dashboard.ConfigOverview = openerp.base.View.extend({ $progress.progressbar({value: $progress.data('completion')}); var self = this; - this.$element.find('div.oe-dashboard-config-overview ul') + this.$element.find('dl') .delegate('input', 'click', function (e) { // switch todo status e.stopImmediatePropagation(); From a5bb1a265b2eb1c217742db34330f28aa0fb78e8 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 25 Aug 2011 14:10:51 +0200 Subject: [PATCH 12/34] [fix] small bug with dates localization bzr revid: nicolas.vanhoren@openerp.com-20110825121051-x86pjeyfnnb65ucr --- addons/base/static/src/js/core.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/base/static/src/js/core.js b/addons/base/static/src/js/core.js index fca993ffef9..57b3a8cb637 100644 --- a/addons/base/static/src/js/core.js +++ b/addons/base/static/src/js/core.js @@ -567,8 +567,8 @@ openerp.base.Session = openerp.base.CallbackEnabled.extend( /** @lends openerp.b self.do_load_js(file_list.concat(files)); }); } else { - self.do_load_css(file_list.concat(["/base/webclient/css?mods="+modules])); - self.do_load_js(["/base/webclient/js?mods="+modules]); + self.do_load_css(["/base/webclient/css?mods="+modules]); + self.do_load_js(file_list.concat(["/base/webclient/js?mods="+modules])); } openerp._modules_loaded = true; }); From 93aa853ae6c047d91e0958607fad73b1a4c5a271 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 25 Aug 2011 14:17:53 +0200 Subject: [PATCH 13/34] [imp] changed format/parse functions for dates to use date.js format instead of the openerp one bzr revid: nicolas.vanhoren@openerp.com-20110825121753-w3acs2fhbwm157a6 --- addons/base/static/src/js/formats.js | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/addons/base/static/src/js/formats.js b/addons/base/static/src/js/formats.js index c141aad908c..ed25b28c16d 100644 --- a/addons/base/static/src/js/formats.js +++ b/addons/base/static/src/js/formats.js @@ -45,8 +45,8 @@ openerp.base.format_value = function (value, descriptor, value_if_empty) { if (typeof(value) == "string") value = openerp.base.str_to_datetime(value); try { - return value.format(_.sprintf("%s %s", openerp.base._t.database.parameters.date_format, - openerp.base._t.database.parameters.time_format)); + return value.toString(_.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate, + Date.CultureInfo.formatPatterns.longTime)); } catch (e) { return value.format("%m/%d/%Y %H:%M:%S"); } @@ -55,7 +55,7 @@ openerp.base.format_value = function (value, descriptor, value_if_empty) { if (typeof(value) == "string") value = openerp.base.str_to_date(value); try { - return value.format(openerp.base._t.database.parameters.date_format); + return value.toString(Date.CultureInfo.formatPatterns.shortDate); } catch (e) { return value.format("%m/%d/%Y"); } @@ -63,7 +63,7 @@ openerp.base.format_value = function (value, descriptor, value_if_empty) { if (typeof(value) == "string") value = openerp.base.str_to_time(value); try { - return value.format(openerp.base._t.database.parameters.time_format); + return value.toString(Date.CultureInfo.formatPatterns.longTime); } catch (e) { return value.format("%H:%M:%S"); } @@ -108,17 +108,27 @@ openerp.base.parse_value = function (value, descriptor, value_if_empty) { case 'progressbar': return openerp.base.parse_value(value, {type: "float"}); case 'datetime': - var tmp = Date.parse(value); + var tmp = Date.parseExact(value, _.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate, + Date.CultureInfo.formatPatterns.longTime)); + if (tmp !== null) + return tmp; + tmp = Date.parse(value); if (tmp !== null) return tmp; throw value + " is not a valid datetime"; case 'date': - var tmp = Date.parse(value); + var tmp = Date.parseExact(Date.CultureInfo.formatPatterns.shortDate); + if (tmp !== null) + return tmp; + tmp = Date.parse(value); if (tmp !== null) return tmp; throw value + " is not a valid date"; case 'time': - var tmp = Date.parse(value); + var tmp = Date.parseExact(Date.CultureInfo.formatPatterns.longTime); + if (tmp !== null) + return tmp; + tmp = Date.parse(value); if (tmp !== null) return tmp; throw value + " is not a valid time"; From b5a429d008536f6410e82b24ee12ec481b6d6397 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 25 Aug 2011 14:30:49 +0200 Subject: [PATCH 14/34] [FIX] fnct_inv in client actions params, fix docstring for fnct_inv (fnct_inv only takes a single record id, not a sequence of ids) bzr revid: xmo@openerp.com-20110825123049-bmvebm86gqgr6w43 --- openerp/addons/base/ir/ir_actions.py | 5 ++--- openerp/osv/fields.py | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openerp/addons/base/ir/ir_actions.py b/openerp/addons/base/ir/ir_actions.py index 0b60d389287..67c36b277dd 100644 --- a/openerp/addons/base/ir/ir_actions.py +++ b/openerp/addons/base/ir/ir_actions.py @@ -936,10 +936,9 @@ class act_client(osv.osv): for record in self.browse(cr, uid, ids, context=context) ]) - def _set_params(self, cr, uid, ids, field_name, field_value, arg, context): + def _set_params(self, cr, uid, id, field_name, field_value, arg, context): assert isinstance(field_value, dict), "params can only be dictionaries" - for record in self.browse(cr, uid, ids, context=context): - record.write({field_name: repr(field_value)}) + self.write(cr, uid, id, {'params_store': repr(field_value)}, context=context) _columns = { 'tag': fields.char('Client action tag', size=64, required=True, diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 782cc8e796a..fb973d2e521 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -852,12 +852,13 @@ class function(_column): This callable implements the write operation for the function field and must have the following signature: - .. function:: fnct_inv(model, cr, uid, ids, field_name, field_value, fnct_inv_arg, context) + .. function:: fnct_inv(model, cr, uid, id, field_name, field_value, fnct_inv_arg, context) Callable that implements the ``write`` operation for the function field. :param orm_template model: model to which the field belongs (should be ``self`` for a model method) + :param int id: the identifier of the object to write on :param str field_name: name of the field to set :param fnct_inv_arg: arbitrary value passed when declaring the function field :return: True From b8cd28fb355de91b9ec736be4f42d77afef0a137 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 25 Aug 2011 14:34:45 +0200 Subject: [PATCH 15/34] [FIX] widgets client action handler: one action per widget bzr revid: xmo@openerp.com-20110825123445-ayhaeipasl4imvqt --- .../base_dashboard/static/src/js/dashboard.js | 61 +++++++++---------- .../static/src/xml/base_dashboard.xml | 9 ++- 2 files changed, 33 insertions(+), 37 deletions(-) diff --git a/addons/base_dashboard/static/src/js/dashboard.js b/addons/base_dashboard/static/src/js/dashboard.js index e5b06a13461..3f9da51b157 100644 --- a/addons/base_dashboard/static/src/js/dashboard.js +++ b/addons/base_dashboard/static/src/js/dashboard.js @@ -372,39 +372,36 @@ openerp.base_dashboard.ApplicationTiles = openerp.base.View.extend({ } }); openerp.base.client_actions.add( - 'board.home.widgets', 'openerp.base_dashboard.Widgets'); -openerp.base_dashboard.Widgets = openerp.base.View.extend({ - template: 'HomeWidgets', - start: function () { - return new openerp.base.DataSetSearch( - this, 'res.widget.user', null, - ['|', ['user_id', '=', false], - ['user_id', '=', parseInt(this.session.uid, 10)]]) - .read_slice(['widget_id', 'user_id'], {}, this.on_widgets_list_loaded); + 'board.home.widgets', 'openerp.base_dashboard.Widget'); +openerp.base_dashboard.Widget = openerp.base.View.extend(/** @lends openerp.base_dashboard.Widgets# */{ + template: 'HomeWidget', + /** + * Initializes a "HomeWidget" client widget: handles the display of a given + * res.widget objects in an OpenERP view (mainly a dashboard). + * + * @constructs + * @extends openerp.base.View + * @param {Object} parent + * @param {Object} options + * @param {Number} options.widget_id + */ + init: function (parent, options) { + this._super(parent); + this.widget_id = options.widget_id; }, - on_widgets_list_loaded: function (user_widgets) { - var self = this; - var widget_user = {}; - _(user_widgets).each(function (widget) { - widget['widget_id'] = widget['widget_id'][0]; - widget_user[widget['widget_id']] = { - removable: widget['user_id'] !== false, - user_widget_id: widget['id'] - }; - }); - new openerp.base.DataSetSearch(this, 'res.widget') - .read_ids(_(user_widgets).pluck('widget_id'), ['title'], function (widgets) { - _(widgets).each(function (widget) { - _.extend(widget, widget_user[widget['id']]); - }); - var url = _.sprintf( - '/base_dashboard/widgets/content?session_id=%s&widget_id=', - self.session.session_id); - self.$element.html(QWeb.render('HomeWidgets', { - widgets: widgets, - url: url - })); - }); + start: function () { + return new openerp.base.DataSet(this, 'res.widget').read_ids( + [this.widget_id], ['title'], this.on_widget_loaded); + }, + on_widget_loaded: function (widgets) { + var widget = widgets[0]; + var url = _.sprintf( + '/base_dashboard/widgets/content?session_id=%s&widget_id=%d', + this.session.session_id, widget.id); + this.$element.html(QWeb.render('HomeWidget.content', { + widget: widget, + url: url + })); } }); }; diff --git a/addons/base_dashboard/static/src/xml/base_dashboard.xml b/addons/base_dashboard/static/src/xml/base_dashboard.xml index 51657dfd068..b60e466964b 100644 --- a/addons/base_dashboard/static/src/xml/base_dashboard.xml +++ b/addons/base_dashboard/static/src/xml/base_dashboard.xml @@ -107,10 +107,9 @@ -
    -
    +
    +

    -