diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index dcb5ae9e4bd..76c32c6b55c 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -241,7 +241,10 @@ def clean_action(action, session): action['domain'], session.evaluation_context( action['context'])) or [] - fix_view_modes(action) + if not action.has_key('flags'): + # Set empty flags dictionary for web client. + action['flags'] = dict() + return fix_view_modes(action) def fix_view_modes(action): """ For historical reasons, OpenERP has weird dealings in relation to @@ -271,6 +274,7 @@ def fix_view_modes(action): [id, mode if mode != 'tree' else 'list'] for id, mode in action['views'] ] + return action class Menu(openerpweb.Controller): _cp_path = "/base/menu" @@ -452,20 +456,49 @@ class DataGroup(openerpweb.Controller): dict(request.context, group_by=group_by_fields)) class View(openerpweb.Controller): + _cp_path = "/base/view" + def fields_view_get(self, request, model, view_id, view_type, transform=True, toolbar=False, submenu=False): Model = request.session.model(model) fvg = Model.fields_view_get(view_id, view_type, request.context, toolbar, submenu) + self.process_view(request.session, fvg, request.context, transform) + return fvg + + def process_view(self, session, fvg, context, transform): if transform: - evaluation_context = request.session.evaluation_context( - request.context or {}) - xml = self.transform_view( - fvg['arch'], request.session, evaluation_context) + evaluation_context = session.evaluation_context(context or {}) + xml = self.transform_view(fvg['arch'], session, evaluation_context) else: xml = ElementTree.fromstring(fvg['arch']) fvg['arch'] = Xml2Json.convert_element(xml) - return fvg + for field in fvg['fields'].values(): + if field.has_key('views') and field['views']: + for view in field["views"].values(): + self.process_view(session, view, None, transform) + + @openerpweb.jsonrequest + def add_custom(self, request, view_id, arch): + CustomView = request.session.model('ir.ui.view.custom') + CustomView.create({ + 'user_id': request.session._uid, + 'ref_id': view_id, + 'arch': arch + }) + return {'result': True} + + @openerpweb.jsonrequest + def undo_custom(self, request, view_id, reset=False): + CustomView = request.session.model('ir.ui.view.custom') + vcustom = CustomView.search([('user_id', '=', request.session._uid), ('ref_id' ,'=', view_id)]) + if vcustom: + if reset: + CustomView.unlink(vcustom) + else: + CustomView.unlink([vcustom[0]]) + return {'result': True} + return {'result': False} def normalize_attrs(self, elem, context): """ Normalize @attrs, @invisible, @required, @readonly and @states, so @@ -693,12 +726,12 @@ class Action(openerpweb.Controller): _cp_path = "/base/action" @openerpweb.jsonrequest - def load(self, req, action_id, context={}): + def load(self, req, action_id): Actions = req.session.model('ir.actions.actions') value = False - action_type = Actions.read([action_id], ['type'], context) + action_type = Actions.read([action_id], ['type'], req.session.context) if action_type: - action = req.session.model(action_type[0]['type']).read([action_id], False, context) + action = req.session.model(action_type[0]['type']).read([action_id], False, req.session.context) if action: - value = action[0] + value = clean_action(action[0], req.session) return {'result': value} diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index ffe23ad16a3..b801fb69f09 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -61,19 +61,71 @@ body.openerp { /* Login */ .openerp .login { display: none; - padding: 6px; - z-index: 1002; - width: 34%; - position: fixed; - top: 0; - left: 33%; +} +.openerp .login form { + float: left; + width: 420px; + margin-left: 40px; + margin-bottom: 60px; +} +.openerp .login fieldset { + padding-bottom: 5px; + min-width: 100px; + margin-top: 60px; + border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; +} +.openerp .login fieldset legend { + padding: 4px; +} +.openerp .login .oe_box2 { + padding: 5px 5px 20px 5px; +} +.openerp .login .oe_box2 table { + width: 100%; + border:none; +} +.openerp .login .oe_box2 td { + padding: 3px; + text-align: right; +} +.openerp .login .oe_box2 td input { + width: 100%; +} +.openerp .login .oe_login_right_pane { + padding:70px 35px 5px 10px; + min-width: 200px; + margin-left: 500px; +} +.openerp .login .login_error_message { + display: none; + background-color: #9A0404; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + color: white; + font-family: Ubuntu, Helvetica, sans-serif; + font-size: 16px; + font-weight: bold; + padding: 5px; + margin-top: 5px; + text-align: center; +} +.openerp .login.login_invalid .login_error_message { + display: block; +} +.openerp.login-mode .login-container { + height: 100%; } -.openerp .login_valid { - background-color: #8f8; +.openerp.login-mode .login { + display: block; } -.openerp .login_invalid { - background-color: #f88; +.openerp.login-mode .menu, +.openerp.login-mode .secondary_menu, +.openerp.login-mode .oe-application { + display: none; } /* Main*/ diff --git a/addons/base/static/src/img/accessories-archiver.png b/addons/base/static/src/img/accessories-archiver.png new file mode 100644 index 00000000000..8bcbe4566bc Binary files /dev/null and b/addons/base/static/src/img/accessories-archiver.png differ diff --git a/addons/base/static/src/img/partner.png b/addons/base/static/src/img/partner.png new file mode 100644 index 00000000000..aab206a1d42 Binary files /dev/null and b/addons/base/static/src/img/partner.png differ diff --git a/addons/base/static/src/img/product.png b/addons/base/static/src/img/product.png new file mode 100644 index 00000000000..99f58d95a8b Binary files /dev/null and b/addons/base/static/src/img/product.png differ diff --git a/addons/base/static/src/img/stock_person.png b/addons/base/static/src/img/stock_person.png new file mode 100644 index 00000000000..202cf0ee6c5 Binary files /dev/null and b/addons/base/static/src/img/stock_person.png differ diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js index cb4c8070b2b..82fecd2df41 100644 --- a/addons/base/static/src/js/chrome.js +++ b/addons/base/static/src/js/chrome.js @@ -172,7 +172,9 @@ openerp.base.BasicController = Class.extend( /** @lends openerp.base.BasicContro init: function(element_id) { this.element_id = element_id; this.$element = $('#' + element_id); - openerp.screen[element_id] = this; + if (element_id) { + openerp.screen[element_id] = this; + } // Transform on_* method into openerp.base.callbacks for (var name in this) { @@ -379,7 +381,7 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b } else { error_callback(response.error); } - } else { + } else if (success_callback) { success_callback(response["result"], textStatus, jqXHR); } }, @@ -449,6 +451,13 @@ openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.b this.set_cookie('uid', this.uid); this.set_cookie('session_id', this.session_id); }, + logout: function() { + this.uid = this.get_cookie('uid'); + this.session_id = this.get_cookie('session_id'); + this.set_cookie('uid', ''); + this.set_cookie('session_id', ''); + this.on_session_invalid(function() {}); + }, /** * Fetches a cookie stored by an openerp session * @@ -785,14 +794,14 @@ openerp.base.Login = openerp.base.Controller.extend({ on_login_invalid: function() { this.$element .removeClass("login_valid") - .addClass("login_invalid") - .show(); + .addClass("login_invalid"); + this.$element.closest(".openerp").addClass("login-mode"); }, on_login_valid: function() { this.$element .removeClass("login_invalid") - .addClass("login_valid") - .hide(); + .addClass("login_valid"); + this.$element.closest(".openerp").removeClass("login-mode"); }, on_submit: function(ev) { ev.preventDefault(); @@ -818,6 +827,9 @@ openerp.base.Login = openerp.base.Controller.extend({ unique: true, callback: continuation }); + }, + on_logout: function() { + this.session.logout(); } }); @@ -830,7 +842,9 @@ openerp.base.Header = openerp.base.Controller.extend({ }, do_update: function() { this.$element.html(QWeb.render("Header", this)); - } + this.$element.find(".logout").click(this.on_logout); + }, + on_logout: function() {} }); openerp.base.Menu = openerp.base.Controller.extend({ @@ -945,6 +959,7 @@ openerp.base.WebClient = openerp.base.Controller.extend({ this.header = new openerp.base.Header(this.session, "oe_header"); this.login = new openerp.base.Login(this.session, "oe_login"); + this.header.on_logout.add(this.login.on_logout); this.session.on_session_invalid.add(this.login.do_ask_login); this.session.on_session_valid.add_last(this.header.do_update); diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js index b7739a3da27..3706b653651 100644 --- a/addons/base/static/src/js/data.js +++ b/addons/base/static/src/js/data.js @@ -310,6 +310,7 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base. }, callback); }, unlink: function(ids) { + // to implement in children this.notification.notify("Unlink", ids); }, call: function (method, ids, args, callback) { @@ -343,15 +344,25 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base. }); openerp.base.DataSetStatic = openerp.base.DataSet.extend({ - init: function(session, model) { + init: function(session, model, ids) { this._super(session, model); // all local records - this.ids = []; - this.count = 0; + this.ids = ids || []; + this.count = this.ids.length; }, read_slice: function (fields, offset, limit, callback) { var end_pos = limit && limit !== -1 ? offset + limit : undefined; this.read_ids(this.ids.slice(offset, end_pos), fields, callback); + }, + set_ids: function (ids) { + this.ids = ids; + this.count = this.ids.length; + }, + unlink: function(ids) { + this.on_unlink(ids); + }, + on_unlink: function(ids) { + this.set_ids(_.without.apply(null, [this.ids].concat(ids))); } }); diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index d225a9cb47a..b2d3e60b321 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -37,8 +37,12 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV }, start: function() { //this.log('Starting FormView '+this.model+this.view_id) - return this.rpc("/base/formview/load", {"model": this.model, "view_id": this.view_id, - toolbar:!!this.flags.sidebar}, this.on_loaded); + if (this.embedded_view) { + return $.Deferred().then(this.on_loaded).resolve({fields_view: this.embedded_view}); + } else { + return this.rpc("/base/formview/load", {"model": this.model, "view_id": this.view_id, + toolbar:!!this.flags.sidebar}, this.on_loaded); + } }, on_loaded: function(data) { var self = this; @@ -84,9 +88,9 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV this.datarecord = record; for (var f in this.fields) { var field = this.fields[f]; + field.touched = false; field.set_value(this.datarecord[f] || false); field.validate(); - field.touched = false; } if (!record.id) { // New record: Second pass in order to trigger the onchanges @@ -309,7 +313,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormV this.notification.notify("Cancelling form"); }, do_update_sidebar: function() { - if (this.view_manager.action.flags.sidebar === false) { + if (this.flags.sidebar === false) { return; } if (!this.datarecord.id) { @@ -750,6 +754,7 @@ openerp.base.form.FieldFloat = openerp.base.form.FieldChar.extend({ set_value: function(value) { if (!value) { // As in GTK client, floats default to 0 + this.touched = this.view.touched = true; value = 0; } this._super.apply(this, [value]); @@ -992,55 +997,67 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({ } }); -openerp.base.form.FieldOne2ManyDatasSet = openerp.base.DataSetStatic.extend({ - start: function() { - }, - write: function (id, data, callback) { - this._super(id, data, callback); - }, - unlink: function() { - this.notification.notify('Unlinking o2m ' + this.ids); - } -}); - -openerp.base.form.FieldOne2ManyViewManager = openerp.base.ViewManager.extend({ - init: function(session, element_id, dataset, views) { - this._super(session, element_id, dataset, views); - this.action = {flags:{}}; - } -}); - openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({ init: function(view, node) { this._super(view, node); this.template = "FieldOne2Many"; - this.operations = []; + this.is_started = $.Deferred(); + this.is_setted = $.Deferred(); }, start: function() { this._super.apply(this, arguments); - this.log("o2m.start"); - var views = [ [false,"list"], [false,"form"] ]; - 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); + + var self = this; + + this.dataset = new openerp.base.DataSetStatic(this.session, this.field.relation); + this.dataset.on_unlink.add_last(function(ids) { + // TODO niv check form view + var view = self.viewmanager.views[self.viewmanager.active_view].controller; + view.reload_content(); + // TODO niv make real suppression (list or direct) + self.on_ui_change(); + }); + + var modes = this.node.attrs.mode; + modes = !!modes ? modes.split(",") : ["tree", "form"]; + var views = []; + _.each(modes, function(mode) { + var view = [false, mode == "tree" ? "list" : mode]; + if (self.field.views && self.field.views[mode]) { + view.push(self.field.views[mode]); + } + views.push(view); + }); + + this.viewmanager = new openerp.base.ViewManager(this.view.session, + this.element_id, this.dataset, views); + this.viewmanager.on_controller_inited.add_last(function(view_type, controller) { + if (view_type == "list") { + // TODO niv + } else if (view_type == "form") { + // TODO niv + } + self.is_started.resolve(); + }); this.viewmanager.start(); + + $.when(this.is_started, this.is_setted).then(function() { + if (modes[0] == "tree") { + var view = self.viewmanager.views[self.viewmanager.active_view].controller; + view.reload_content(); + } + // TODO niv: handle other types of views + }); }, set_value: function(value) { - this.value = value; - if (value != false) { - this.log("o2m.set_value",value); - this.viewmanager.dataset.ids = value; - this.viewmanager.dataset.count = value.length; + if(value != false) { + this.dataset.set_ids(value); + this.is_setted.resolve(); } }, get_value: function(value) { - return this.operations; - }, - update_dom: function() { - this._super.apply(this, arguments); - this.$element.toggleClass('disabled', this.readonly); - this.$element.toggleClass('required', this.required); - }, - on_ui_change: function() { + //TODO niv + return []; } }); @@ -1049,59 +1066,48 @@ openerp.base.form.FieldMany2Many = openerp.base.form.Field.extend({ this._super(view, node); this.template = "FieldMany2Many"; this.list_id = _.uniqueId("many2many"); - this.is_started = false; - this.is_setted = false; + this.is_started = $.Deferred(); + this.is_setted = $.Deferred(); }, start: function() { this._super.apply(this, arguments); + + var self = this; + this.dataset = new openerp.base.DataSetStatic( this.session, this.field.relation); + this.dataset.on_unlink.add_last(function(ids) { + self.list_view.reload_content(); + + self.on_ui_change(); + }); this.list_view = new openerp.base.form.Many2ManyListView( null, this.view.session, this.list_id, this.dataset, false, { 'selectable': false, 'addable': 'Add' }); - this.list_view.groups.datagroup = ( - new openerp.base.StaticDataGroup(this.dataset)); - var self = this; this.list_view.m2m_field = this; this.list_view.start(); - var hack = {loaded: false}; this.list_view.on_loaded.add_last(function() { - if (! hack.loaded) { - self.is_started = true; - self.check_load(); - hack.loaded = true; - } + self.is_started.resolve(); + }); + $.when(this.is_started, this.is_setted).then(function() { + self.list_view.reload_content(); }); }, set_value: function(value) { if (value != false) { - this.dataset.ids = value; - this.dataset.count = value.length; - this.is_setted = true; - this.check_load(); + this.dataset.set_ids(value); + this.is_setted.resolve(); } }, get_value: function() { return [[6,false,this.dataset.ids]]; - }, - check_load: function() { - if(this.is_started && this.is_setted) { - this.list_view.reload_content(); - } } }); openerp.base.form.Many2ManyListView = openerp.base.ListView.extend({ - do_delete: function (ids) { - this.dataset.ids = _.without.apply(null, [this.dataset.ids].concat(ids)); - this.dataset.count = this.dataset.ids.length; - this.reload_content(); - - this.m2m_field.on_ui_change(); - }, do_add_record: function () { var pop = new openerp.base.form.Many2XSelectPopup( null, this.m2m_field.view.session); @@ -1109,8 +1115,7 @@ openerp.base.form.Many2ManyListView = openerp.base.ListView.extend({ var self = this; pop.on_select_element.add(function(element_id) { if(! _.detect(self.dataset.ids, function(x) {return x == element_id;})) { - self.dataset.ids.push(element_id); - self.dataset.count = self.dataset.ids.length; + self.dataset.set_ids([].concat(self.dataset.ids, [element_id])); self.reload_content(); } pop.stop(); @@ -1178,7 +1183,7 @@ openerp.base.form.Many2XSelectPopup = openerp.base.BaseWidget.extend({ var tmphack = {"loaded": false}; self.view_list.on_loaded.add_last(function() { if ( !tmphack.loaded ) { - self.view_list.reload_view(); + self.searchview.do_search(); tmphack.loaded = true; }; }); diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 7bcfc26c61b..6081c8c0eb8 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -52,9 +52,13 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi this.columns = []; this.options = _.extend({}, this.defaults, options || {}); - this.flags = this.view_manager.action.flags; + this.flags = this.view_manager.flags || {}; this.set_groups(new openerp.base.ListView.Groups(this)); + + if (this.dataset instanceof openerp.base.DataSetStatic) { + this.groups.datagroup = new openerp.base.StaticDataGroup(this.dataset); + } }, /** * Set a custom Group construct as the root of the List View. @@ -254,14 +258,19 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi var self = this; this.dataset.offset = 0; this.dataset.limit = false; - return this.rpc('/base/listview/load', { - model: this.model, - view_id: this.view_id, - toolbar: !!this.flags.sidebar, - context: this.dataset.context - }, function (field_view_get) { - self.on_loaded(field_view_get, grouped); - }); + var callback = function (field_view_get) { + self.on_loaded(field_view_get, grouped); + }; + if (this.embedded_view) { + return $.Deferred().then(callback).resolve({fields_view: this.embedded_view}); + } else { + return this.rpc('/base/listview/load', { + model: this.model, + view_id: this.view_id, + context: this.dataset.context, + toolbar: !!this.flags.sidebar + }, callback); + } }, /** * re-renders the content of the list view diff --git a/addons/base/static/src/js/search.js b/addons/base/static/src/js/search.js index e5e726f98eb..4c23f64bcbb 100644 --- a/addons/base/static/src/js/search.js +++ b/addons/base/static/src/js/search.js @@ -3,7 +3,7 @@ openerp.base.search = function(openerp) { openerp.base.SearchView = openerp.base.Controller.extend({ init: function(view_manager, session, element_id, dataset, view_id, defaults) { this._super(session, element_id); - this.view_manager = view_manager; + this.view_manager = view_manager || new openerp.base.NullViewManager(); this.dataset = dataset; this.model = dataset.model; this.view_id = view_id; diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index a83c38cc006..4c259babd8f 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -67,7 +67,7 @@ openerp.base.ActionManager = openerp.base.Controller.extend({ dialog.stop(); break; default: - console.log(_.sprintf("Action manager can't handle action of type %s", action.type), action); + console.log("Action manager can't handle action of type " + action.type, action); } } }); @@ -95,7 +95,8 @@ openerp.base.ViewManager = openerp.base.Controller.extend({ self.on_mode_switch($(this).data('view-type')); }); _.each(this.views_src, function(view) { - self.views[view[1]] = { view_id: view[0], controller: null }; + self.views[view[1]] = { view_id: view[0], controller: null, + embedded_view: view[2]}; }); if (this.flags.views_switcher === false) { this.$element.find('.oe_vm_switch').hide(); @@ -119,7 +120,14 @@ openerp.base.ViewManager = openerp.base.Controller.extend({ // Lazy loading of views var controllerclass = openerp.base.views.get_object(view_type); var controller = new controllerclass( this, this.session, this.element_id + "_view_" + view_type, this.dataset, view.view_id); + if (view.embedded_view) { + controller.set_embedded_view(view.embedded_view); + } view_promise = controller.start(); + var self = this; + $.when(view_promise).then(function() { + self.on_controller_inited(view_type, controller); + }); this.views[view_type].controller = controller; } @@ -147,6 +155,13 @@ openerp.base.ViewManager = openerp.base.Controller.extend({ } return view_promise; }, + /** + * Event launched when a controller has been inited. + * + * @param {String} view_type type of view + * @param {String} view the inited controller + */ + on_controller_inited: function(view_type, view) {}, /** * Sets up the current viewmanager's search view. * @@ -384,6 +399,16 @@ openerp.base.View = openerp.base.Controller.extend({ return dataset.exec_workflow(record_id, action_data.name, handler); } } + }, + /** + * Directly set a view to use instead of calling fields_view_get. This method must + * be called before start(). When an embedded view is set, underlying implementations + * of openerp.base.View must use the provided view instead of any other one. + * + * @param embedded_view A view. + */ + set_embedded_view: function(embedded_view) { + this.embedded_view = embedded_view; } }); diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index f1c1d3df4cf..03b33c117da 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -17,7 +17,6 @@
#{text}
-| @@ -34,6 +33,11 @@ | |
| + + | +|