[MERGE] niv sidebar action

bzr revid: al@openerp.com-20110409201421-9dk19e0jbt25oh9b
This commit is contained in:
Antony Lesuisse 2011-04-09 22:14:21 +02:00
commit 39c554b192
8 changed files with 146 additions and 74 deletions

View File

@ -9,6 +9,8 @@ import openerpweb
import openerpweb.ast
import openerpweb.nonliterals
import cherrypy
# Should move to openerpweb.Xml2Json
class Xml2Json:
# xml2json-direct
@ -168,26 +170,71 @@ class Session(openerpweb.Controller):
'domain': domain,
'group_by': group_by_sequence
}
@openerpweb.jsonrequest
def save_session_action(self, req, the_action):
"""
This method store an action object in the session object and returns an integer
identifying that action. The method get_session_action() can be used to get
back the action.
:param the_action: The action to save in the session.
:type the_action: anything
:return: A key identifying the saved action.
:rtype: integer
"""
saved_actions = cherrypy.session.get('saved_actions')
if not saved_actions:
saved_actions = {"next":0, "actions":{}}
cherrypy.session['saved_actions'] = saved_actions
# we don't allow more than 10 stored actions
if len(saved_actions["actions"]) >= 10:
del saved_actions["actions"][min(saved_actions["actions"].keys())]
key = saved_actions["next"]
saved_actions["actions"][key] = the_action
saved_actions["next"] = key + 1
return key
@openerpweb.jsonrequest
def get_session_action(self, req, key):
"""
Gets back a previously saved action. This method can return None if the action
was saved since too much time (this case should be handled in a smart way).
:param key: The key given by save_session_action()
:type key: integer
:return: The saved action or None.
:rtype: anything
"""
saved_actions = cherrypy.session.get('saved_actions')
if not saved_actions:
return None
return saved_actions["actions"].get(key)
def load_actions_from_ir_values(req, key, key2, models, meta, context):
Values = req.session.model('ir.values')
actions = Values.get(key, key2, models, meta, context)
for _, _, action in actions:
# values come from the server, we can just eval them
if isinstance(action['context'], basestring):
action['context'] = eval(
action['context'],
req.session.evaluation_context()) or {}
clean_action(action, req.session)
if isinstance(action['domain'], basestring):
action['domain'] = eval(
action['domain'],
req.session.evaluation_context(
action['context'])) or []
fix_view_modes(action)
return actions
def clean_action(action, session):
# values come from the server, we can just eval them
if isinstance(action['context'], basestring):
action['context'] = eval(
action['context'],
session.evaluation_context()) or {}
if isinstance(action['domain'], basestring):
action['domain'] = eval(
action['domain'],
session.evaluation_context(
action['context'])) or []
fix_view_modes(action)
def fix_view_modes(action):
""" For historical reasons, OpenERP has weird dealings in relation to
view_mode and the view_type attribute (on window actions):
@ -354,9 +401,9 @@ class DataSet(openerpweb.Controller):
return {'result': r}
class View(openerpweb.Controller):
def fields_view_get(self, session, model, view_id, view_type, transform=True):
def fields_view_get(self, session, model, view_id, view_type, transform=True, toolbar=False, submenu=False):
Model = session.model(model)
r = Model.fields_view_get(view_id, view_type)
r = Model.fields_view_get(view_id, view_type, {}, toolbar, submenu)
if transform:
context = {} # TODO: dict(ctx_sesssion, **ctx_action)
xml = self.transform_view(r['arch'], session, context)
@ -460,16 +507,16 @@ class FormView(View):
_cp_path = "/base/formview"
@openerpweb.jsonrequest
def load(self, req, model, view_id):
fields_view = self.fields_view_get(req.session, model, view_id, 'form')
def load(self, req, model, view_id, toolbar=False):
fields_view = self.fields_view_get(req.session, model, view_id, 'form', toolbar=toolbar)
return {'fields_view': fields_view}
class ListView(View):
_cp_path = "/base/listview"
@openerpweb.jsonrequest
def load(self, req, model, view_id):
fields_view = self.fields_view_get(req.session, model, view_id, 'tree')
def load(self, req, model, view_id, toolbar=False):
fields_view = self.fields_view_get(req.session, model, view_id, 'tree', toolbar=toolbar)
return {'fields_view': fields_view}
class SearchView(View):
@ -479,15 +526,6 @@ class SearchView(View):
def load(self, req, model, view_id):
fields_view = self.fields_view_get(req.session, model, view_id, 'search')
return {'fields_view': fields_view}
class SideBar(View):
_cp_path = "/base/sidebar"
@openerpweb.jsonrequest
def get_actions(self, request, model, object_id=0):
result = load_actions_from_ir_values(request, "action", "client_action_multi",
[[model, object_id]], False, {})
return result
class Action(openerpweb.Controller):
_cp_path = "/base/action"

View File

@ -3,7 +3,7 @@
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>OpenERP</title>
<link rel="shortcut icon" href="/base/static/openerp/img/favicon.ico" type="image/x-icon"/>
<link rel="shortcut icon" href="/base/static/src/img/favicon.ico" type="image/x-icon"/>
<script type="text/javascript" src="/base/static/lib/LABjs/LAB.js"></script>
<script type="text/javascript" src="/base/static/lib/underscore/underscore.js"></script>

View File

@ -99,7 +99,7 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
context: this.context
}, callback);
},
unlink: function() {
unlink: function(ids) {
this.notification['default']("Unlink", ids);
},
call: function (method, ids, args, callback) {
@ -111,7 +111,7 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
ids: ids,
args: args
}, callback);
},
}
});
openerp.base.DataSetStatic = openerp.base.DataSet.extend({
@ -123,7 +123,7 @@ openerp.base.DataSetStatic = openerp.base.DataSet.extend({
},
read_slice: function (fields, offset, limit, callback) {
this.read_ids(this.ids.slice(offset, offset + limit));
},
}
});
openerp.base.DataSetSearch = openerp.base.DataSet.extend({
@ -163,7 +163,7 @@ openerp.base.DataSetSearch = openerp.base.DataSet.extend({
}
callback(records);
});
},
}
});
openerp.base.DataSetRelational = openerp.base.DataSet.extend( /** @lends openerp.base.DataSet# */{

View File

@ -30,7 +30,8 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base
},
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}, this.on_loaded);
return this.rpc("/base/formview/load", {"model": this.model, "view_id": this.view_id,
toolbar:!!this.view_manager.sidebar}, this.on_loaded);
},
on_loaded: function(data) {
var self = this;
@ -54,7 +55,7 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base
// sidebar stuff
if (this.view_manager.sidebar) {
this.view_manager.sidebar.load_multi_actions();
this.view_manager.sidebar.set_toolbar(data.fields_view.toolbar);
}
},
do_show: function () {
@ -140,7 +141,7 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base
var ajax = {
url: '/base/dataset/call',
async: false
}
};
return this.rpc(ajax, {
model: this.dataset.model,
method: method,
@ -212,7 +213,7 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base
if (invalid) {
this.on_invalid();
} else {
this.log("About to save", values)
this.log("About to save", values);
this.dataset.write(this.datarecord.id, values, this.on_saved);
}
},
@ -244,8 +245,13 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base
}
},
do_search: function (domains, contexts, groupbys) {
this.notification['default']("Searching form");
},
on_action: function (action) {
this.notification['default']('Executing action ' + action);
},
do_cancel: function () {
this.notification['default']("Cancelling form");
}
});
@ -698,7 +704,7 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
},
set_value: function(value) {
this._super.apply(this, arguments);
var show_value = ''
var show_value = '';
if (value != null && value !== false) {
show_value = value[1];
this.value = value[0];
@ -713,17 +719,15 @@ openerp.base.form.FieldOne2ManyDatasSet = openerp.base.DataSetStatic.extend({
write: function (id, data, callback) {
this._super(id, data, callback);
},
write: function (id, data, callback) {
this._super(id, data, callback);
},
unlink: function() {
this.notification['default']('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);
},
}
});
openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({

View File

@ -36,7 +36,8 @@ openerp.base.ListView = openerp.base.Controller.extend(
},
start: function() {
//this.log('Starting ListView '+this.model+this.view_id)
return this.rpc("/base/listview/load", {"model": this.model, "view_id":this.view_id}, this.on_loaded);
return this.rpc("/base/listview/load", {"model": this.model, "view_id":this.view_id,
toolbar:!!this.view_manager.sidebar}, this.on_loaded);
},
on_loaded: function(data) {
this.fields_view = data.fields_view;
@ -73,8 +74,9 @@ openerp.base.ListView = openerp.base.Controller.extend(
'tr', 'click', this.on_select_row);
// sidebar stuff
if (this.view_manager.sidebar)
this.view_manager.sidebar.load_multi_actions();
if (this.view_manager.sidebar) {
this.view_manager.sidebar.set_toolbar(data.fields_view.toolbar);
}
},
/**
* Fills the table with the provided records after emptying it
@ -83,7 +85,6 @@ openerp.base.ListView = openerp.base.Controller.extend(
* @returns {Promise} promise to the end of view rendering (list views are asynchronously filled for improved responsiveness)
*/
do_fill_table: function(records) {
console.log("listview do_fill",records)
this.rows = records;
var $table = this.$element.find('table');
@ -148,7 +149,6 @@ openerp.base.ListView = openerp.base.Controller.extend(
},
do_search: function (domains, contexts, groupbys) {
var self = this;
console.log("listview do_search",domains)
this.rpc('/base/session/eval_domain_and_context', {
domains: domains,
contexts: contexts,

View File

@ -20,7 +20,7 @@ openerp.base.ActionManager = openerp.base.Controller.extend({
if (this.viewmanager) {
this.viewmanager.stop();
}
this.viewmanager = new openerp.base.ViewManagerAction(this.session,this.element_id, action, false);
this.viewmanager = new openerp.base.ViewManagerAction(this.session,this.element_id, action, true);
this.viewmanager.start();
}
}
@ -141,7 +141,6 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({
this.sidebar = new openerp.base.Sidebar(null, this);
},
start: function() {
var self = this;
var inital_view_loaded = this._super();
// init sidebar
@ -159,10 +158,13 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({
search_defaults[match[1]] = value;
}
});
var searchview_loaded = this.setup_search_view(view_id,search_defaults);
var searchview_loaded = null;
if (view_id) {
searchview_loaded = this.setup_search_view(view_id,search_defaults);
}
// schedule auto_search
if (this.action['auto_search']) {
if (searchview_loaded != null && this.action['auto_search']) {
$.when(searchview_loaded, inital_view_loaded)
.then(this.searchview.do_search);
}
@ -173,29 +175,30 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({
this.sidebar.stop();
}
this._super();
},
}
});
openerp.base.BaseWidget = openerp.base.Controller.extend({
/**
* The name of the QWeb template that will be used for rendering. Must be redifined
* in subclasses or the render() method can not be used.
* The name of the QWeb template that will be used for rendering. Must be
* redefined in subclasses or the render() method can not be used.
*
* @type string
*/
template: null,
/**
* The prefix used to generate an id automatically. Should be redifined in subclasses.
* If it is not defined, a default identifier will be used.
* The prefix used to generate an id automatically. Should be redefined in
* subclasses. If it is not defined, a default identifier will be used.
*
* @type string
*/
identifier_prefix: 'generic-identifier',
/**
* Base class for widgets. Handle rendering (based on a QWeb template), identifier
* generation, parenting and destruction of the widget.
* Contructor. Also initialize the identifier.
*
* Base class for widgets. Handle rendering (based on a QWeb template),
* identifier generation, parenting and destruction of the widget.
* Also initialize the identifier.
*
* @constructs
* @params {openerp.base.search.BaseWidget} parent The parent widget.
*/
init: function (parent, session) {
@ -242,8 +245,8 @@ openerp.base.BaseWidget = openerp.base.Controller.extend({
this._super();
},
/**
* Set the parent of this component, also unregister the previous parent if there
* was one.
* Set the parent of this component, also un-register the previous parent
* if there was one.
*
* @param {openerp.base.BaseWidget} parent The new parent.
*/
@ -274,27 +277,26 @@ openerp.base.Sidebar = openerp.base.BaseWidget.extend({
this.view_manager = view_manager;
this.sections = [];
},
load_multi_actions: function() {
if (_.detect(this.sections, function(x) {return x.type=="multi_actions";}) != undefined)
return;
set_toolbar: function(toolbar) {
this.sections = [];
var self = this;
this.rpc("/base/sidebar/get_actions",
{"model": this.view_manager.dataset.model}, function(result) {
self.sections.push({type: "multi_actions", elements:
_.map(result, function(x) {return {text:x[2].name, action:x}; })});
self.refresh();
_.each(["print", "action", "relate"], function(type) {
if (toolbar[type].length == 0)
return;
var section = {elements:toolbar[type]};
self.sections.push(section);
});
this.refresh();
},
refresh: function() {
this.$element.html(QWeb.render("ViewManager.sidebar.internal", _.extend({_:_}, this)));
var self = this;
this.$element.find("a").click(function(e) {
$this = jQuery(this);
var $this = jQuery(this);
var i = $this.attr("data-i");
var j = $this.attr("data-i");
var j = $this.attr("data-j");
var action = self.sections[i].elements[j];
// I know this doesn't work, one day it will
new openerp.base.ActionManager(this.view_manager, null).do_action(action);
(new openerp.base.ExternalActionManager(self.view_manager.session, null)) .handle_action(action);
e.stopPropagation();
e.preventDefault();
});
@ -305,6 +307,30 @@ openerp.base.Sidebar = openerp.base.BaseWidget.extend({
}
});
openerp.base.ExternalActionManager = openerp.base.Controller.extend({
handle_action: function(action) {
if(action.type=="ir.actions.act_window") {
if(action.target=="new") {
var element_id = _.uniqueId("act_window_dialog");
var dialog = $('<div id="'+element_id+'"></div>');
dialog.dialog({
title: action.name
});
var viewmanager = new openerp.base.ViewManagerAction(this.session ,element_id, action, false);
viewmanager.start();
} else if (action.target == "current") {
this.rpc("/base/session/save_session_action", {the_action:action}, function(key) {
var url = window.location.href;
//window.open();
});
}
}
// TODO: show an error like "not implemented" here
// since we don't currently have any way to handle errors do you have any better idea
// than using todos?
}
});
openerp.base.views.add('calendar', 'openerp.base.CalendarView');
openerp.base.CalendarView = openerp.base.Controller.extend({
start: function () {

View File

@ -533,8 +533,8 @@
<ul>
<t t-set="j" t-value="0"/>
<t t-foreach="section.elements" t-as="element">
<li><a t-att-data-i="i" t-att-data-j="j" href="#"><t t-esc="element.text"/></a></li>
<t t-set="j+1" t-value="0"/>
<li><a t-att-data-i="i" t-att-data-j="j" href="#"><t t-esc="element.name"/></a></li>
<t t-set="j" t-value="j+1"/>
</t>
</ul>
</t>

View File

@ -18,6 +18,7 @@ import simplejson
import nonliterals
import xmlrpctimeout
import logging
#-----------------------------------------------------------
# Globals
@ -355,6 +356,8 @@ class JsonRequest(object):
}
}
except Exception:
cherrypy.log("An error occured while handling a json request",
severity=logging.ERROR, traceback=True)
error = {
'code': 300,
'message': "OpenERP WebClient Error",
@ -495,3 +498,4 @@ def main(argv):
cherrypy.server.subscribe()
cherrypy.engine.start()
cherrypy.engine.block()