diff --git a/addons/base/static/lib/qweb/qweb2.js b/addons/base/static/lib/qweb/qweb2.js index 5067d30d70e..5041142924d 100644 --- a/addons/base/static/lib/qweb/qweb2.js +++ b/addons/base/static/lib/qweb/qweb2.js @@ -35,10 +35,10 @@ var QWeb2 = { return (noquotes ? '' : "'") + s.replace(/\r?\n/g, "\\n").replace(/'/g, "\\'") + (noquotes ? '' : "'"); }, html_escape: function(s, attribute) { - if (s === null || s === undefined) { + if (s == null) { return ''; } - s = (new String(s)).replace(/&/g, '&').replace(//g, '>'); + s = String(s).replace(/&/g, '&').replace(//g, '>'); if (attribute) { s = s.replace(/"/g, '"'); } diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index 30dc3718fa9..9749dc97110 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -547,11 +547,27 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%, } .openerp .searchview_extended_group { - border: #696969 solid 1px; padding: 3px; margin: 2px; } +.openerp .searchview_extended_group .oe_adv_filters_and { + border-bottom: 1px solid #8E8E8E; + text-align: center; + margin-top: -10px; +} +.openerp .searchview_extended_group .oe_adv_filters_and span { + background: #F0EEEE; + position: relative; + top: 0.5em; + padding: 0 1em 0 1em; + color: #8E8E8E; +} + +.openerp .searchview_extended_group.last_group .oe_adv_filters_and { + display: none; +} + .openerp .oe_search-view-custom-filter-btn span { background: url(../img/icons/gtk-add.png) repeat-y; padding-left: 18px; @@ -565,6 +581,7 @@ background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%, .openerp .searchview_extended_delete_group { float:right; + display: none; } .openerp .searchview_extended_delete_group span, @@ -1042,3 +1059,14 @@ background: linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* W3C */ .openerp .oe-m2o-disabled-cm { color: grey; } + +.openerp .oe-dialog-warning { + font-size: 1.2em; + font-weight: bold; +} +.openerp .oe-dialog-warning img { + float: left; + position: relative; + top: -0.5em; + margin:0 7px 7px 0; +} diff --git a/addons/base/static/src/img/warning.png b/addons/base/static/src/img/warning.png new file mode 100644 index 00000000000..cbfb25a89cd Binary files /dev/null and b/addons/base/static/src/img/warning.png differ diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js index 84aa4acc325..2bea20fe972 100644 --- a/addons/base/static/src/js/chrome.js +++ b/addons/base/static/src/js/chrome.js @@ -739,36 +739,47 @@ openerp.base.Dialog = openerp.base.BaseWidget.extend({ identifier_prefix: 'dialog', init: function (session, options) { this._super(null, session); - options = _.extend({ + this.options = { modal: true, - title: this.dialog_title, - width: '700px', + width: 'auto', min_width: 0, max_width: '100%', - height: '500px', + height: 'auto', min_height: 0, max_height: '100%', + autoOpen: false, buttons: {} - }, options); - - options.width = this.get_width(options.width); - options.min_width = this.get_width(options.min_width); - options.max_width = this.get_width(options.max_width); - options.height = this.get_height(options.height); - options.min_height = this.get_height(options.min_height); - options.max_height = this.get_height(options.max_height); - - if (options.width > options.max_width) options.width = options.max_width; - if (options.width < options.min_width) options.width = options.min_width; - if (options.height > options.max_height) options.height = options.max_height; - if (options.height < options.min_height) options.height = options.min_height; - + }; for (var f in this) { if (f.substr(0, 10) == 'on_button_') { - options.buttons[f.substr(10)] = this[f]; + this.options.buttons[f.substr(10)] = this[f]; } } - this.options = options; + if (options) { + this.set_options(options); + } + }, + set_options: function(options) { + options = options || {}; + options.width = this.get_width(options.width || this.options.width); + options.min_width = this.get_width(options.min_width || this.options.min_width); + options.max_width = this.get_width(options.max_width || this.options.max_width); + options.height = this.get_height(options.height || this.options.height); + options.min_height = this.get_height(options.min_height || this.options.min_height); + options.max_height = this.get_height(options.max_height || this.options.max_width); + + if (options.width !== 'auto') { + if (options.width > options.max_width) options.width = options.max_width; + if (options.width < options.min_width) options.width = options.min_width; + } + if (options.height !== 'auto') { + if (options.height > options.max_height) options.height = options.max_height; + if (options.height < options.min_height) options.height = options.min_height; + } + if (!options.title && this.dialog_title) { + options.title = this.dialog_title; + } + _.extend(this.options, options); }, get_width: function(val) { return this.get_size(val.toString(), $(window.top).width()); @@ -777,7 +788,7 @@ openerp.base.Dialog = openerp.base.BaseWidget.extend({ return this.get_size(val.toString(), $(window.top).height()); }, get_size: function(val, available_size) { - if (val == 'auto') { + if (val === 'auto') { return val; } else if (val.slice(-1) == "%") { return Math.round(available_size / 100 * parseInt(val.slice(0, -1), 10)); @@ -785,33 +796,55 @@ openerp.base.Dialog = openerp.base.BaseWidget.extend({ return parseInt(val, 10); } }, - start: function () { + start: function (auto_open) { this.$dialog = $('
').dialog(this.options); + if (auto_open !== false) { + this.open(); + } this._super(); }, + open: function(options) { + // TODO fme: bind window on resize + if (this.template) { + this.$element.html(this.render()); + } + this.set_options(options); + this.$dialog.dialog(this.options).dialog('open'); + }, + close: function(options) { + this.$dialog.dialog('close'); + }, stop: function () { - this.$dialog("destroy").remove(); + this.$dialog.dialog('destroy'); } }); -openerp.base.CrashManager = openerp.base.Controller.extend({ - init: function(session, element_id) { - this._super(session, element_id); +openerp.base.CrashManager = openerp.base.Dialog.extend({ + identifier_prefix: 'dialog_crash', + init: function(session) { + this._super(session); 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); + on_button_Ok: function() { + this.close(); }, - display_error: function(message) { - $('
').text(message).dialog({
-            modal: true,
-            buttons: {
-                OK: function() {
-                    $(this).dialog("close");
-                }
-            }
-        });
+    on_rpc_error: function(error) {
+        this.error = error;
+        if (error.code === 200) {
+            this.dialog_title = "OpenERP Warning";
+            this.template = 'DialogWarning';
+            this.open({
+                width: 'auto',
+                height: 'auto'
+            });
+        } else {
+            this.dialog_title = "OpenERP Error";
+            this.template = 'DialogTraceback';
+            this.open({
+                width: '80%',
+                height: '80%'
+            });
+        }
     }
 });
 
@@ -1041,6 +1074,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);
+        this.crashmanager.start(false);
 
         // Do you autorize this ?
         openerp.base.Controller.prototype.notification = new openerp.base.Notification("oe_notification");
diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js
index 1463ca279fa..736c31c1f7b 100644
--- a/addons/base/static/src/js/data.js
+++ b/addons/base/static/src/js/data.js
@@ -287,11 +287,12 @@ openerp.base.DataSet =  openerp.base.Controller.extend( /** @lends openerp.base.
             });
         }
     },
-    default_get: function(fields, callback) {
+    default_get: function(fields, context, callback) {
+        context = context || this.context;
         return this.rpc('/base/dataset/default_get', {
             model: this.model,
             fields: fields,
-            context: this.context
+            context: context
         }, callback);
     },
     create: function(data, callback, error_callback) {
diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js
index 90357325928..d221872598d 100644
--- a/addons/base/static/src/js/form.js
+++ b/addons/base/static/src/js/form.js
@@ -1,4 +1,3 @@
-
 openerp.base.form = function (openerp) {
 
 openerp.base.views.add('form', 'openerp.base.FormView');
@@ -43,8 +42,12 @@ openerp.base.FormView =  openerp.base.View.extend( /** @lends openerp.base.FormV
         if (this.embedded_view) {
             return $.Deferred().then(this.on_loaded).resolve({fields_view: this.embedded_view});
         } else {
+            var context = new openerp.base.CompoundContext(this.dataset.context);
+            if (this.view_manager.action && this.view_manager.action.context) {
+                context.add(this.view_manager.action.context);
+            }
             return this.rpc("/base/formview/load", {"model": this.model, "view_id": this.view_id,
-                toolbar:!!this.flags.sidebar}, this.on_loaded);
+                toolbar:!!this.flags.sidebar, context: context}, this.on_loaded);
         }
     },
     on_loaded: function(data) {
@@ -226,8 +229,12 @@ openerp.base.FormView =  openerp.base.View.extend( /** @lends openerp.base.FormV
     },
     on_button_new: function() {
         var self = this;
+        var context = new openerp.base.CompoundContext(this.dataset.context);
+        if (this.view_manager.action && this.view_manager.action.context) {
+            context.add(this.view_manager.action.context);
+        }
         $.when(this.has_been_loaded).then(function() {
-            self.dataset.default_get(_.keys(self.fields_view.fields), function(result) {
+            self.dataset.default_get(_.keys(self.fields_view.fields), context, function(result) {
                 self.on_record_loaded(result.result);
             });
         });
@@ -299,6 +306,7 @@ openerp.base.FormView =  openerp.base.View.extend( /** @lends openerp.base.FormV
             if (success) {
                 success(r);
             }
+            this.reload();
         }
     },
     /**
@@ -333,6 +341,7 @@ openerp.base.FormView =  openerp.base.View.extend( /** @lends openerp.base.FormV
             if (success) {
                 success(_.extend(r, {created: true}));
             }
+            this.reload();
         }
     },
     do_search: function (domains, contexts, groupbys) {
@@ -995,7 +1004,7 @@ openerp.base.form.FieldSelection = openerp.base.form.Field.extend({
         if (value != null && value !== false) {
             this.$element.find('select').val(value);
         } else {
-            this.$element.find('select')[0].selectedIndex = 0;
+            this.$element.find('select').val('false');
         }
     },
     set_value_from_ui: function() {
diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js
index b4528de5afd..bd2518dcb66 100644
--- a/addons/base/static/src/js/list.js
+++ b/addons/base/static/src/js/list.js
@@ -571,7 +571,7 @@ openerp.base.ListView.List = Class.extend( /** @lends openerp.base.ListView.List
             this.$current.remove();
         }
         this.$current = this.$_element.clone(true);
-        this.$current.empty().append($(QWeb.render('ListView.rows', this)));
+        this.$current.empty().append(QWeb.render('ListView.rows', this));
     },
     get_fields_view: function () {
         // deep copy of view
diff --git a/addons/base/static/src/js/search.js b/addons/base/static/src/js/search.js
index 4c23f64bcbb..cd69ec4f0e8 100644
--- a/addons/base/static/src/js/search.js
+++ b/addons/base/static/src/js/search.js
@@ -731,6 +731,7 @@ openerp.base.search.ExtendedSearch = openerp.base.BaseWidget.extend({
         var render = group.render();
         this.$element.find('.searchview_extended_groups_list').append(render);
         group.start();
+        this.check_last_element();
     },
     start: function () {
         this._super();
@@ -758,11 +759,9 @@ openerp.base.search.ExtendedSearch = openerp.base.BaseWidget.extend({
     on_activate: function() {
         this.add_group();
         var table = this.$element.closest("table.oe-searchview-render-line");
-        if(table.css("display") == "none") {
-            table.css("display", "");
-            if(this.$element.hasClass("folded")) {
-                this.$element.toggleClass("folded expanded");
-            }
+        table.css("display", "");
+        if(this.$element.hasClass("folded")) {
+            this.$element.toggleClass("folded expanded");
         }
     },
     hide: function() {
@@ -771,6 +770,10 @@ openerp.base.search.ExtendedSearch = openerp.base.BaseWidget.extend({
         if(this.$element.hasClass("expanded")) {
             this.$element.toggleClass("folded expanded");
         }
+    },
+    check_last_element: function() {
+        _.each(this.children, function(x) {x.set_last_group(false);});
+        this.children[this.children.length - 1].set_last_group(true);
     }
 });
 
@@ -796,9 +799,6 @@ openerp.base.search.ExtendedSearchGroup = openerp.base.BaseWidget.extend({
         });
         var delete_btn = this.$element.find('.searchview_extended_delete_group');
         delete_btn.click(function (e) {
-            if (_this.parent.children.length == 1)  {
-                _this.parent.hide();
-            }
             _this.stop();
         });
     },
@@ -811,6 +811,19 @@ openerp.base.search.ExtendedSearchGroup = openerp.base.BaseWidget.extend({
         return [].concat(choice == "none" ? ['!'] : [],
             _.map(_.range(_.max([0,props.length - 1])), function() { return op; }),
             props);
+    },
+    stop: function() {
+        var parent = this.parent;
+        if (this.parent.children.length == 1)
+            this.parent.hide();
+        this._super();
+        parent.check_last_element();
+    },
+    set_last_group: function(is_last) {
+        if(is_last)
+            this.$element.addClass("last_group");
+        else
+            this.$element.removeClass("last_group");
     }
 });
 
@@ -838,6 +851,11 @@ openerp.base.search.ExtendedSearchProposition = openerp.base.BaseWidget.extend({
             _this.stop();
         });
     },
+    stop: function() {
+        if (this.parent.children.length == 1)
+            this.parent.stop();
+        this._super();
+    },
     changed: function() {
         var nval = this.$element.find(".searchview_extended_prop_field").val();
         if(this.attrs.selected == null || nval != this.attrs.selected.name) {
diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js
index 4217031a7e3..ee910d57cfd 100644
--- a/addons/base/static/src/js/views.js
+++ b/addons/base/static/src/js/views.js
@@ -397,10 +397,22 @@ openerp.base.View = openerp.base.Controller.extend({
      */
     execute_action: function (action_data, dataset, action_manager, record_id, on_no_action) {
         var handler = function (r) {
-            if (r.result && r.result.constructor == Object) {
-                action_manager.do_action(r.result);
+            var action = r.result;
+            if (action && action.constructor == Object) {
+                action.context = action.context || {};
+                action.context['active_id'] = dataset.ids[dataset.index];
+                action.context['active_ids'] = [dataset.ids[dataset.index]];
+                action.context['active_model'] = dataset.model;
+                action.flags = {
+                    sidebar : false,
+                    search_view : false,
+                    views_switcher : false,
+                    action_buttons : false,
+                    pager : false
+                };
+                action_manager.do_action(action);
             } else {
-                on_no_action(r.result);
+                on_no_action(action);
             }
         };
 
@@ -409,12 +421,12 @@ openerp.base.View = openerp.base.Controller.extend({
                 result : { type: 'ir.actions.act_window_close' }
             });
         } else {
-            var context = _.extend({}, dataset.context, action_data.context || {});
+            var context = new openerp.base.CompoundContext(dataset.context).add(action_data.context || {});
             switch(action_data.type) {
                 case 'object':
-                    return dataset.call(action_data.name, [[record_id], context], handler);
+                    return dataset.call_and_eval(action_data.name, [[record_id], context], null, 1, handler);
                 case 'action':
-                    return this.rpc('/base/action/load', { action_id: parseInt(action_data.name, 10) }, handler);
+                    return this.rpc('/base/action/load', { action_id: parseInt(action_data.name, 10), context: context }, handler);
                 default:
                     return dataset.exec_workflow(record_id, action_data.name, handler);
             }
diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml
index 949b38e0115..b03bb044ba4 100644
--- a/addons/base/static/src/xml/base.xml
+++ b/addons/base/static/src/xml/base.xml
@@ -90,7 +90,7 @@
                             t-att-value="selected_password || ''"/>
                     
                     
-                        
+                        
                         
                             
                             
@@ -804,6 +804,7 @@
         
         
             Add condition
+        
and
@@ -870,12 +871,15 @@ -
-

- - -

-
+

+ + +

+
+ +
+
+
diff --git a/openerpweb/nonliterals.py b/openerpweb/nonliterals.py index 40913cb628e..643ee8a393b 100644 --- a/openerpweb/nonliterals.py +++ b/openerpweb/nonliterals.py @@ -6,7 +6,6 @@ can't be sent there themselves). """ import binascii import hashlib -import simplejson.decoder import simplejson.encoder __all__ = ['Domain', 'Context', 'NonLiteralEncoder, non_literal_decoder'] @@ -17,6 +16,8 @@ SHORT_HASH_BYTES_SIZE = 6 class NonLiteralEncoder(simplejson.encoder.JSONEncoder): def default(self, object): + if not isinstance(object, (BaseDomain, BaseContext)): + return super(NonLiteralEncoder, self).default(object) if isinstance(object, Domain): return { '__ref': 'domain', @@ -30,14 +31,14 @@ class NonLiteralEncoder(simplejson.encoder.JSONEncoder): elif isinstance(object, CompoundDomain): return { '__ref': 'compound_domain', - '__domains': [self.default(el) for el in object.domains] + '__domains': object.domains } elif isinstance(object, CompoundContext): return { '__ref': 'compound_context', - '__contexts': [self.default(el) for el in object.contexts] + '__contexts': object.contexts } - return super(NonLiteralEncoder, self).default(object) + raise TypeError('Could not encode unknown non-literal %s' % object) def non_literal_decoder(dct): """ Decodes JSON dicts into :class:`Domain` and :class:`Context` based on @@ -69,7 +70,16 @@ def non_literal_decoder(dct): return ccontext return dct -class Domain(object): +# TODO: use abstract base classes if 2.6+? +class BaseDomain(object): + def evaluate(self, context=None): + raise NotImplementedError('Non literals must implement evaluate()') + +class BaseContext(object): + def evaluate(self, context=None): + raise NotImplementedError('Non literals must implement evaluate()') + +class Domain(BaseDomain): def __init__(self, session, domain_string=None, key=None): """ Uses session information to store the domain string and map it to a domain key, which can be safely round-tripped to the client. @@ -113,7 +123,7 @@ class Domain(object): ctx.update(self.own) return eval(self.get_domain_string(), ctx) -class Context(object): +class Context(BaseContext): def __init__(self, session, context_string=None, key=None): """ Uses session information to store the context string and map it to a key (stored in a secret location under a secret mountain), which can @@ -159,7 +169,7 @@ class Context(object): return eval(self.get_context_string(), ctx) -class CompoundDomain: +class CompoundDomain(BaseDomain): def __init__(self, *domains): self.domains = [] self.session = None @@ -169,7 +179,7 @@ class CompoundDomain: def evaluate(self, context=None): final_domain = [] for domain in self.domains: - if not isinstance(domain, (list, Domain, CompoundDomain)): + if not isinstance(domain, (list, BaseDomain)): raise TypeError("Domain %r is not a list or a nonliteral Domain", domain) @@ -188,7 +198,7 @@ class CompoundDomain: self.domains.append(domain) return self -class CompoundContext: +class CompoundContext(BaseContext): def __init__(self, *contexts): self.contexts = [] self.session = None @@ -199,7 +209,7 @@ class CompoundContext: ctx = dict(context or {}) final_context = {} for context_to_eval in self.contexts: - if not isinstance(context_to_eval, (dict, Context, CompoundContext)): + if not isinstance(context_to_eval, (dict, BaseContext)): raise TypeError("Context %r is not a dict or a nonliteral Context", context_to_eval) diff --git a/openerpweb/tests/test_session.py b/openerpweb/tests/test_session.py index ebf66e6289d..991a1d061ec 100644 --- a/openerpweb/tests/test_session.py +++ b/openerpweb/tests/test_session.py @@ -77,7 +77,7 @@ class TestOpenERPSession(unittest2.TestCase): def test_eval_empty_domains(self): self.assertEqual( - self.session.eval_domain(CompoundDomain(*[])), + self.session.eval_domain(CompoundDomain()), []) def test_eval_literal_domains(self):