2009-10-20 10:52:23 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
2006-12-07 13:41:40 +00:00
|
|
|
##############################################################################
|
|
|
|
#
|
2009-09-30 11:20:35 +00:00
|
|
|
# OpenERP, Open Source Management Solution
|
2009-10-14 12:32:15 +00:00
|
|
|
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
2011-05-12 12:37:52 +00:00
|
|
|
# Copyright (C) 2010-2011 OpenERP SA (<http://openerp.com>).
|
2006-12-07 13:41:40 +00:00
|
|
|
#
|
2008-11-03 18:27:16 +00:00
|
|
|
# This program is free software: you can redistribute it and/or modify
|
2009-10-14 12:32:15 +00:00
|
|
|
# it under the terms of the GNU Affero General Public License as
|
|
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
|
|
# License, or (at your option) any later version.
|
2006-12-07 13:41:40 +00:00
|
|
|
#
|
2008-11-03 18:27:16 +00:00
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2009-10-14 12:32:15 +00:00
|
|
|
# GNU Affero General Public License for more details.
|
2006-12-07 13:41:40 +00:00
|
|
|
#
|
2009-10-14 12:32:15 +00:00
|
|
|
# You should have received a copy of the GNU Affero General Public License
|
2008-11-03 18:27:16 +00:00
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2006-12-07 13:41:40 +00:00
|
|
|
#
|
|
|
|
##############################################################################
|
|
|
|
|
2010-11-25 14:22:19 +00:00
|
|
|
import base64
|
2008-07-11 11:42:24 +00:00
|
|
|
import re
|
2010-11-25 14:22:19 +00:00
|
|
|
|
2008-09-16 12:26:07 +00:00
|
|
|
import tools
|
2011-04-20 15:27:18 +00:00
|
|
|
import openerp.modules
|
2010-11-25 14:22:19 +00:00
|
|
|
from osv import fields, osv
|
2010-11-18 16:47:21 +00:00
|
|
|
from tools.translate import _
|
2006-12-07 13:41:40 +00:00
|
|
|
|
|
|
|
def one_in(setA, setB):
|
2008-07-22 14:24:36 +00:00
|
|
|
"""Check the presence of an element of setA in setB
|
|
|
|
"""
|
|
|
|
for x in setA:
|
|
|
|
if x in setB:
|
|
|
|
return True
|
|
|
|
return False
|
2006-12-07 13:41:40 +00:00
|
|
|
|
|
|
|
class ir_ui_menu(osv.osv):
|
2008-07-22 14:24:36 +00:00
|
|
|
_name = 'ir.ui.menu'
|
2008-10-09 07:29:00 +00:00
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
self._cache = {}
|
2008-10-16 18:28:16 +00:00
|
|
|
r = super(ir_ui_menu, self).__init__(*args, **kwargs)
|
|
|
|
self.pool.get('ir.model.access').register_cache_clearing_method(self._name, 'clear_cache')
|
|
|
|
return r
|
|
|
|
|
2008-10-09 07:29:00 +00:00
|
|
|
def clear_cache(self):
|
|
|
|
# radical but this doesn't frequently happen
|
|
|
|
self._cache = {}
|
|
|
|
|
2010-12-10 16:17:08 +00:00
|
|
|
def _filter_visible_menus(self, cr, uid, ids, context=None):
|
|
|
|
"""Filters the give menu ids to only keep the menu items that should be
|
|
|
|
visible in the menu hierarchy of the current user.
|
|
|
|
Uses a cache for speeding up the computation.
|
|
|
|
"""
|
2008-10-09 07:29:00 +00:00
|
|
|
modelaccess = self.pool.get('ir.model.access')
|
2008-10-31 20:44:01 +00:00
|
|
|
user_groups = set(self.pool.get('res.users').read(cr, 1, uid, ['groups_id'])['groups_id'])
|
2008-07-22 14:24:36 +00:00
|
|
|
result = []
|
2010-12-10 16:17:08 +00:00
|
|
|
for menu in self.browse(cr, uid, ids, context=context):
|
2008-10-09 07:29:00 +00:00
|
|
|
# this key works because user access rights are all based on user's groups (cfr ir_model_access.check)
|
|
|
|
key = (cr.dbname, menu.id, tuple(user_groups))
|
|
|
|
if key in self._cache:
|
|
|
|
if self._cache[key]:
|
|
|
|
result.append(menu.id)
|
2010-04-19 22:09:47 +00:00
|
|
|
#elif not menu.groups_id and not menu.action:
|
|
|
|
# result.append(menu.id)
|
2008-07-22 14:24:36 +00:00
|
|
|
continue
|
2008-10-09 07:29:00 +00:00
|
|
|
|
|
|
|
self._cache[key] = False
|
|
|
|
if menu.groups_id:
|
|
|
|
restrict_to_groups = [g.id for g in menu.groups_id]
|
|
|
|
if not user_groups.intersection(restrict_to_groups):
|
|
|
|
continue
|
2010-06-11 12:55:43 +00:00
|
|
|
#result.append(menu.id)
|
|
|
|
#self._cache[key] = True
|
|
|
|
#continue
|
2008-10-09 07:29:00 +00:00
|
|
|
|
2008-10-31 20:44:01 +00:00
|
|
|
if menu.action:
|
2008-10-09 07:29:00 +00:00
|
|
|
# we check if the user has access to the action of the menu
|
2010-03-17 14:04:54 +00:00
|
|
|
data = menu.action
|
2008-10-09 07:29:00 +00:00
|
|
|
if data:
|
|
|
|
model_field = { 'ir.actions.act_window': 'res_model',
|
2009-09-30 11:20:35 +00:00
|
|
|
'ir.actions.report.xml': 'model',
|
2008-10-09 07:29:00 +00:00
|
|
|
'ir.actions.wizard': 'model',
|
|
|
|
'ir.actions.server': 'model_id',
|
|
|
|
}
|
|
|
|
|
2010-03-17 14:04:54 +00:00
|
|
|
field = model_field.get(menu.action._name)
|
2008-10-09 07:29:00 +00:00
|
|
|
if field and data[field]:
|
|
|
|
if not modelaccess.check(cr, uid, data[field], raise_exception=False):
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
# if there is no action, it's a 'folder' menu
|
|
|
|
if not menu.child_id:
|
2009-09-30 11:20:35 +00:00
|
|
|
# not displayed if there is no children
|
2008-10-09 07:29:00 +00:00
|
|
|
continue
|
|
|
|
|
2008-09-23 16:24:56 +00:00
|
|
|
result.append(menu.id)
|
2008-10-31 20:44:01 +00:00
|
|
|
self._cache[key] = True
|
2010-12-10 16:17:08 +00:00
|
|
|
return result
|
|
|
|
|
|
|
|
def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
|
|
|
|
if context is None:
|
|
|
|
context = {}
|
|
|
|
|
|
|
|
ids = super(ir_ui_menu, self).search(cr, uid, args, offset=0,
|
|
|
|
limit=None, order=order, context=context, count=False)
|
|
|
|
|
|
|
|
if not ids:
|
|
|
|
if count:
|
|
|
|
return 0
|
|
|
|
return []
|
|
|
|
|
|
|
|
# menu filtering is done only on main menu tree, not other menu lists
|
|
|
|
if context.get('ir.ui.menu.full_list'):
|
|
|
|
result = ids
|
|
|
|
else:
|
|
|
|
result = self._filter_visible_menus(cr, uid, ids, context=context)
|
2008-10-09 07:29:00 +00:00
|
|
|
|
2010-05-13 07:30:31 +00:00
|
|
|
if offset:
|
|
|
|
result = result[long(offset):]
|
|
|
|
if limit:
|
|
|
|
result = result[:long(limit)]
|
|
|
|
|
2008-10-09 07:29:00 +00:00
|
|
|
if count:
|
|
|
|
return len(result)
|
2008-07-22 14:24:36 +00:00
|
|
|
return result
|
2006-12-07 13:41:40 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def _get_full_name(self, cr, uid, ids, name, args, context):
|
|
|
|
res = {}
|
|
|
|
for m in self.browse(cr, uid, ids, context=context):
|
|
|
|
res[m.id] = self._get_one_full_name(m)
|
|
|
|
return res
|
2006-12-07 13:41:40 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def _get_one_full_name(self, menu, level=6):
|
|
|
|
if level<=0:
|
|
|
|
return '...'
|
|
|
|
if menu.parent_id:
|
|
|
|
parent_path = self._get_one_full_name(menu.parent_id, level-1) + "/"
|
|
|
|
else:
|
|
|
|
parent_path = ''
|
|
|
|
return parent_path + menu.name
|
2006-12-07 13:41:40 +00:00
|
|
|
|
2010-12-10 16:17:08 +00:00
|
|
|
def create(self, *args, **kwargs):
|
|
|
|
self.clear_cache()
|
|
|
|
return super(ir_ui_menu, self).create(*args, **kwargs)
|
|
|
|
|
2008-10-09 07:29:00 +00:00
|
|
|
def write(self, *args, **kwargs):
|
|
|
|
self.clear_cache()
|
|
|
|
return super(ir_ui_menu, self).write(*args, **kwargs)
|
|
|
|
|
|
|
|
def unlink(self, *args, **kwargs):
|
|
|
|
self.clear_cache()
|
|
|
|
return super(ir_ui_menu, self).unlink(*args, **kwargs)
|
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def copy(self, cr, uid, id, default=None, context=None):
|
|
|
|
ir_values_obj = self.pool.get('ir.values')
|
|
|
|
res = super(ir_ui_menu, self).copy(cr, uid, id, context=context)
|
|
|
|
datas=self.read(cr,uid,[res],['name'])[0]
|
|
|
|
rex=re.compile('\([0-9]+\)')
|
|
|
|
concat=rex.findall(datas['name'])
|
|
|
|
if concat:
|
2010-09-02 10:41:07 +00:00
|
|
|
next_num=int(concat[0])+1
|
2008-07-22 14:24:36 +00:00
|
|
|
datas['name']=rex.sub(('(%d)'%next_num),datas['name'])
|
|
|
|
else:
|
|
|
|
datas['name']=datas['name']+'(1)'
|
|
|
|
self.write(cr,uid,[res],{'name':datas['name']})
|
|
|
|
ids = ir_values_obj.search(cr, uid, [
|
|
|
|
('model', '=', 'ir.ui.menu'),
|
|
|
|
('res_id', '=', id),
|
|
|
|
])
|
|
|
|
for iv in ir_values_obj.browse(cr, uid, ids):
|
2010-02-04 17:24:36 +00:00
|
|
|
ir_values_obj.copy(cr, uid, iv.id, default={'res_id': res},
|
|
|
|
context=context)
|
2008-07-22 14:24:36 +00:00
|
|
|
return res
|
2006-12-07 13:41:40 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def _action(self, cursor, user, ids, name, arg, context=None):
|
|
|
|
res = {}
|
2011-05-16 15:05:34 +00:00
|
|
|
ir_values_obj = self.pool.get('ir.values')
|
|
|
|
value_ids = ir_values_obj.search(cursor, user, [
|
2008-07-22 14:24:36 +00:00
|
|
|
('model', '=', self._name), ('key', '=', 'action'),
|
|
|
|
('key2', '=', 'tree_but_open'), ('res_id', 'in', ids)],
|
|
|
|
context=context)
|
|
|
|
values_action = {}
|
2011-05-16 15:05:34 +00:00
|
|
|
for value in ir_values_obj.browse(cursor, user, value_ids, context=context):
|
2008-07-22 14:24:36 +00:00
|
|
|
values_action[value.res_id] = value.value
|
|
|
|
for menu_id in ids:
|
|
|
|
res[menu_id] = values_action.get(menu_id, False)
|
|
|
|
return res
|
2007-10-19 12:14:58 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def _action_inv(self, cursor, user, menu_id, name, value, arg, context=None):
|
|
|
|
if context is None:
|
|
|
|
context = {}
|
|
|
|
ctx = context.copy()
|
2009-01-15 11:57:18 +00:00
|
|
|
if self.CONCURRENCY_CHECK_FIELD in ctx:
|
|
|
|
del ctx[self.CONCURRENCY_CHECK_FIELD]
|
2011-05-16 15:05:34 +00:00
|
|
|
ir_values_obj = self.pool.get('ir.values')
|
|
|
|
values_ids = ir_values_obj.search(cursor, user, [
|
2008-07-22 14:24:36 +00:00
|
|
|
('model', '=', self._name), ('key', '=', 'action'),
|
|
|
|
('key2', '=', 'tree_but_open'), ('res_id', '=', menu_id)],
|
|
|
|
context=context)
|
|
|
|
if values_ids:
|
2011-05-16 15:05:34 +00:00
|
|
|
ir_values_obj.write(cursor, user, values_ids, {'value': value},
|
2008-07-22 14:24:36 +00:00
|
|
|
context=ctx)
|
2009-09-30 11:20:35 +00:00
|
|
|
else:
|
2011-05-16 15:05:34 +00:00
|
|
|
ir_values_obj.create(cursor, user, {
|
2008-07-22 14:24:36 +00:00
|
|
|
'name': 'Menuitem',
|
|
|
|
'model': self._name,
|
|
|
|
'value': value,
|
|
|
|
'object': True,
|
|
|
|
'key': 'action',
|
|
|
|
'key2': 'tree_but_open',
|
|
|
|
'res_id': menu_id,
|
|
|
|
}, context=ctx)
|
2008-09-18 14:02:05 +00:00
|
|
|
|
2008-07-25 10:26:00 +00:00
|
|
|
def _get_icon_pict(self, cr, uid, ids, name, args, context):
|
|
|
|
res = {}
|
|
|
|
for m in self.browse(cr, uid, ids, context=context):
|
|
|
|
res[m.id] = ('stock', (m.icon,'ICON_SIZE_MENU'))
|
|
|
|
return res
|
2008-09-16 12:26:07 +00:00
|
|
|
|
2008-07-25 10:26:00 +00:00
|
|
|
def onchange_icon(self, cr, uid, ids, icon):
|
|
|
|
if not icon:
|
|
|
|
return {}
|
|
|
|
return {'type': {'icon_pict': 'picture'}, 'value': {'icon_pict': ('stock', (icon,'ICON_SIZE_MENU'))}}
|
2007-10-19 12:14:58 +00:00
|
|
|
|
2010-11-24 10:49:36 +00:00
|
|
|
def read_image(self, path):
|
2011-05-12 12:37:52 +00:00
|
|
|
if not path:
|
|
|
|
return False
|
2010-11-25 10:50:02 +00:00
|
|
|
path_info = path.split(',')
|
2011-04-20 15:27:18 +00:00
|
|
|
icon_path = openerp.modules.get_module_resource(path_info[0],path_info[1])
|
2011-01-04 04:34:15 +00:00
|
|
|
icon_image = False
|
2010-12-31 09:32:40 +00:00
|
|
|
if icon_path:
|
2011-01-06 17:38:28 +00:00
|
|
|
try:
|
|
|
|
icon_file = tools.file_open(icon_path,'rb')
|
|
|
|
icon_image = base64.encodestring(icon_file.read())
|
|
|
|
finally:
|
|
|
|
icon_file.close()
|
2010-12-31 09:32:40 +00:00
|
|
|
return icon_image
|
2010-11-24 10:49:36 +00:00
|
|
|
|
2011-05-12 12:37:52 +00:00
|
|
|
def _get_image_icon(self, cr, uid, ids, names, args, context=None):
|
2010-11-24 10:49:36 +00:00
|
|
|
res = {}
|
|
|
|
for menu in self.browse(cr, uid, ids, context=context):
|
2011-05-12 12:37:52 +00:00
|
|
|
res[menu.id] = r = {}
|
|
|
|
for fn in names:
|
|
|
|
fn_src = fn[:-5] # remove _data
|
|
|
|
r[fn] = self.read_image(menu[fn_src])
|
|
|
|
|
2010-11-24 10:49:36 +00:00
|
|
|
return res
|
2010-07-19 11:34:29 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
_columns = {
|
|
|
|
'name': fields.char('Menu', size=64, required=True, translate=True),
|
|
|
|
'sequence': fields.integer('Sequence'),
|
2009-01-26 17:40:29 +00:00
|
|
|
'child_id' : fields.one2many('ir.ui.menu', 'parent_id','Child IDs'),
|
2008-07-22 14:24:36 +00:00
|
|
|
'parent_id': fields.many2one('ir.ui.menu', 'Parent Menu', select=True),
|
2010-12-19 20:07:51 +00:00
|
|
|
'groups_id': fields.many2many('res.groups', 'ir_ui_menu_group_rel',
|
2009-01-26 17:40:29 +00:00
|
|
|
'menu_id', 'gid', 'Groups', help="If you have groups, the visibility of this menu will be based on these groups. "\
|
2010-08-10 11:22:58 +00:00
|
|
|
"If this field is empty, OpenERP will compute visibility based on the related object's read access."),
|
2008-07-22 14:24:36 +00:00
|
|
|
'complete_name': fields.function(_get_full_name, method=True,
|
|
|
|
string='Complete Name', type='char', size=128),
|
2008-09-16 12:26:07 +00:00
|
|
|
'icon': fields.selection(tools.icons, 'Icon', size=64),
|
2009-06-11 09:19:36 +00:00
|
|
|
'icon_pict': fields.function(_get_icon_pict, method=True, type='char', size=32),
|
2010-12-29 09:47:54 +00:00
|
|
|
'web_icon': fields.char('Web Icon File', size=128),
|
|
|
|
'web_icon_hover':fields.char('Web Icon File (hover)', size=128),
|
|
|
|
'web_icon_data': fields.function(_get_image_icon, string='Web Icon Image', type='binary', method=True, readonly=True, store=True, multi='icon'),
|
|
|
|
'web_icon_hover_data':fields.function(_get_image_icon, string='Web Icon Image (hover)', type='binary', method=True, readonly=True, store=True, multi='icon'),
|
2008-07-22 14:24:36 +00:00
|
|
|
'action': fields.function(_action, fnct_inv=_action_inv,
|
|
|
|
method=True, type='reference', string='Action',
|
|
|
|
selection=[
|
|
|
|
('ir.actions.report.xml', 'ir.actions.report.xml'),
|
|
|
|
('ir.actions.act_window', 'ir.actions.act_window'),
|
|
|
|
('ir.actions.wizard', 'ir.actions.wizard'),
|
2008-10-30 07:56:24 +00:00
|
|
|
('ir.actions.url', 'ir.actions.url'),
|
2010-02-04 17:24:36 +00:00
|
|
|
('ir.actions.server', 'ir.actions.server'),
|
2008-10-30 07:56:24 +00:00
|
|
|
]),
|
2008-07-22 14:24:36 +00:00
|
|
|
}
|
2011-01-04 04:34:15 +00:00
|
|
|
|
2010-11-18 16:47:21 +00:00
|
|
|
def _rec_message(self, cr, uid, ids, context=None):
|
|
|
|
return _('Error ! You can not create recursive Menu.')
|
|
|
|
|
2010-07-19 11:34:29 +00:00
|
|
|
_constraints = [
|
2010-12-09 10:57:33 +00:00
|
|
|
(osv.osv._check_recursion, _rec_message , ['parent_id'])
|
2010-07-19 11:34:29 +00:00
|
|
|
]
|
2008-07-22 14:24:36 +00:00
|
|
|
_defaults = {
|
2010-11-23 15:25:51 +00:00
|
|
|
'icon' : 'STOCK_OPEN',
|
|
|
|
'icon_pict': ('stock', ('STOCK_OPEN','ICON_SIZE_MENU')),
|
|
|
|
'sequence' : 10,
|
2008-07-22 14:24:36 +00:00
|
|
|
}
|
|
|
|
_order = "sequence,id"
|
2006-12-07 13:41:40 +00:00
|
|
|
ir_ui_menu()
|
|
|
|
|
|
|
|
|
2008-07-23 15:01:27 +00:00
|
|
|
|
|
|
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
|
|
|