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>).
2012-11-29 17:21:45 +00:00
# Copyright (C) 2010-2012 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
2014-07-06 14:44:26 +00:00
import operator
2008-07-11 11:42:24 +00:00
import re
2012-01-25 11:58:23 +00:00
import threading
2014-07-06 14:44:26 +00:00
2011-04-20 15:27:18 +00:00
import openerp . modules
2012-12-10 15:27:23 +00:00
from openerp . osv import fields , osv
2014-07-06 14:44:26 +00:00
from openerp import api , tools
from openerp . tools . safe_eval import safe_eval as eval
2012-12-10 15:27:23 +00:00
from openerp . tools . translate import _
2006-12-07 13:41:40 +00:00
2013-01-16 17:14:11 +00:00
MENU_ITEM_SEPARATOR = " / "
2014-06-27 09:03:34 +00:00
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 ) :
2014-07-06 14:44:26 +00:00
cls = type ( self )
# by design, self._menu_cache is specific to the database
cls . _menu_cache_lock = threading . RLock ( )
cls . _menu_cache = { }
2012-12-14 12:25:25 +00:00
super ( ir_ui_menu , self ) . __init__ ( * args , * * kwargs )
2008-10-16 18:28:16 +00:00
self . pool . get ( ' ir.model.access ' ) . register_cache_clearing_method ( self . _name , ' clear_cache ' )
2008-10-09 07:29:00 +00:00
def clear_cache ( self ) :
2014-07-06 14:44:26 +00:00
with self . _menu_cache_lock :
2012-01-25 11:58:23 +00:00
# radical but this doesn't frequently happen
2014-07-06 14:44:26 +00:00
if self . _menu_cache :
2012-12-08 18:11:51 +00:00
# Normally this is done by openerp.tools.ormcache
# but since we do not use it, set it by ourself.
self . pool . _any_cache_cleared = True
2014-07-06 14:44:26 +00:00
self . _menu_cache . clear ( )
2014-07-17 15:18:14 +00:00
self . load_menus_root . _orig . clear_cache ( self )
self . load_menus . _orig . clear_cache ( self )
2014-07-06 14:44:26 +00:00
@api.multi
@api.returns ( ' self ' )
def _filter_visible_menus ( self ) :
""" Filter `self` 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 .
2010-12-10 16:17:08 +00:00
"""
2014-07-06 14:44:26 +00:00
with self . _menu_cache_lock :
groups = self . env . user . groups_id
# visibility is entirely based on the user's groups;
# self._menu_cache[key] gives the ids of all visible menus
key = frozenset ( groups . _ids )
if key in self . _menu_cache :
visible = self . browse ( self . _menu_cache [ key ] )
else :
# retrieve all menus, and determine which ones are visible
context = { ' ir.ui.menu.full_list ' : True }
menus = self . with_context ( context ) . search ( [ ] )
# first discard all menus with groups the user does not have
menus = menus . filtered (
lambda menu : not menu . groups_id or menu . groups_id & groups )
# take apart menus that have an action
action_menus = menus . filtered ( ' action ' )
folder_menus = menus - action_menus
visible = self . browse ( )
# process action menus, check whether their action is allowed
access = self . env [ ' ir.model.access ' ]
model_fname = {
' ir.actions.act_window ' : ' res_model ' ,
' ir.actions.report.xml ' : ' model ' ,
' ir.actions.wizard ' : ' model ' ,
' ir.actions.server ' : ' model_id ' ,
}
for menu in action_menus :
fname = model_fname . get ( menu . action . _name )
if not fname or not menu . action [ fname ] or \
access . check ( menu . action [ fname ] , ' read ' , False ) :
# make menu visible, and its folder ancestors, too
visible + = menu
menu = menu . parent_id
while menu and menu in folder_menus and menu not in visible :
visible + = menu
menu = menu . parent_id
self . _menu_cache [ key ] = visible . _ids
return self . filtered ( lambda menu : menu in visible )
2010-12-10 16:17:08 +00:00
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
2012-10-29 10:46:36 +00:00
def name_get ( self , cr , uid , ids , context = None ) :
res = [ ]
for id in ids :
elmt = self . browse ( cr , uid , id , context = context )
res . append ( ( id , self . _get_one_full_name ( elmt ) ) )
return res
def _get_full_name ( self , cr , uid , ids , name = None , args = None , context = None ) :
2012-12-14 12:16:38 +00:00
if context is None :
2012-10-29 10:46:36 +00:00
context = { }
2008-07-22 14:24:36 +00:00
res = { }
2012-10-29 10:46:36 +00:00
for elmt in self . browse ( cr , uid , ids , context = context ) :
res [ elmt . id ] = self . _get_one_full_name ( elmt )
2008-07-22 14:24:36 +00:00
return res
2006-12-07 13:41:40 +00:00
2012-10-29 10:46:36 +00:00
def _get_one_full_name ( self , elmt , level = 6 ) :
2008-07-22 14:24:36 +00:00
if level < = 0 :
return ' ... '
2012-10-29 10:46:36 +00:00
if elmt . parent_id :
2013-01-16 17:14:11 +00:00
parent_path = self . _get_one_full_name ( elmt . parent_id , level - 1 ) + MENU_ITEM_SEPARATOR
2008-07-22 14:24:36 +00:00
else :
parent_path = ' '
2012-10-29 10:46:36 +00:00
return parent_path + elmt . name
2006-12-07 13:41:40 +00:00
2014-07-06 14:44:26 +00:00
def create ( self , cr , uid , values , context = None ) :
2010-12-10 16:17:08 +00:00
self . clear_cache ( )
2014-07-06 14:44:26 +00:00
return super ( ir_ui_menu , self ) . create ( cr , uid , values , context = context )
2010-12-10 16:17:08 +00:00
2014-07-06 14:44:26 +00:00
def write ( self , cr , uid , ids , values , context = None ) :
2008-10-09 07:29:00 +00:00
self . clear_cache ( )
2014-07-06 14:44:26 +00:00
return super ( ir_ui_menu , self ) . write ( cr , uid , ids , values , context = context )
2008-10-09 07:29:00 +00:00
2012-12-13 14:58:21 +00:00
def unlink ( self , cr , uid , ids , context = None ) :
# Detach children and promote them to top-level, because it would be unwise to
# cascade-delete submenus blindly. We also can't use ondelete=set null because
# that is not supported when _parent_store is used (would silently corrupt it).
# TODO: ideally we should move them under a generic "Orphans" menu somewhere?
if isinstance ( ids , ( int , long ) ) :
ids = [ ids ]
local_context = dict ( context or { } )
local_context [ ' ir.ui.menu.full_list ' ] = True
direct_children_ids = self . search ( cr , uid , [ ( ' parent_id ' , ' in ' , ids ) ] , context = local_context )
if direct_children_ids :
self . write ( cr , uid , direct_children_ids , { ' parent_id ' : False } )
result = super ( ir_ui_menu , self ) . unlink ( cr , uid , ids , context = context )
2008-10-09 07:29:00 +00:00
self . clear_cache ( )
2012-12-13 14:58:21 +00:00
return result
2008-10-09 07:29:00 +00:00
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 ' )
2014-07-06 14:44:26 +00:00
res = super ( ir_ui_menu , self ) . copy ( cr , uid , id , default = default , context = context )
2008-07-22 14:24:36 +00:00
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 :
2012-12-14 13:19:24 +00:00
datas [ ' name ' ] + = ' (1) '
2008-07-22 14:24:36 +00:00
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 )
2012-02-10 08:26:37 +00:00
if value and values_ids :
ir_values_obj . write ( cursor , user , values_ids , { ' value ' : value } , context = ctx )
elif value :
# no values_ids, create binding
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 ,
' key ' : ' action ' ,
' key2 ' : ' tree_but_open ' ,
' res_id ' : menu_id ,
} , context = ctx )
2012-02-10 08:26:37 +00:00
elif values_ids :
# value is False, remove existing binding
ir_values_obj . unlink ( cursor , user , values_ids , 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
2012-12-05 10:20:52 +00:00
def _get_needaction_enabled ( self , cr , uid , ids , field_names , args , context = None ) :
""" needaction_enabled: tell whether the menu has a related action
that uses the needaction mechanism . """
res = dict . fromkeys ( ids , False )
for menu in self . browse ( cr , uid , ids , context = context ) :
if menu . action and menu . action . type in ( ' ir.actions.act_window ' , ' ir.actions.client ' ) and menu . action . res_model :
2013-03-29 14:07:23 +00:00
if menu . action . res_model in self . pool and self . pool [ menu . action . res_model ] . _needaction :
2012-12-05 10:20:52 +00:00
res [ menu . id ] = True
return res
def get_needaction_data ( self , cr , uid , ids , context = None ) :
""" Return for each menu entry of ids :
- if it uses the needaction mechanism ( needaction_enabled )
- the needaction counter of the related action , taking into account
the action domain
"""
2013-05-07 10:40:25 +00:00
if context is None :
context = { }
2012-04-18 09:07:35 +00:00
res = { }
2013-04-25 14:28:01 +00:00
menu_ids = set ( )
2012-03-28 16:35:49 +00:00
for menu in self . browse ( cr , uid , ids , context = context ) :
2013-04-25 14:28:01 +00:00
menu_ids . add ( menu . id )
2013-04-17 13:23:39 +00:00
ctx = None
if menu . action and menu . action . type in ( ' ir.actions.act_window ' , ' ir.actions.client ' ) and menu . action . context :
2013-05-07 10:40:25 +00:00
try :
# use magical UnquoteEvalContext to ignore undefined client-side variables such as `active_id`
eval_ctx = tools . UnquoteEvalContext ( * * context )
ctx = eval ( menu . action . context , locals_dict = eval_ctx , nocopy = True ) or None
except Exception :
# if the eval still fails for some reason, we'll simply skip this menu
pass
2013-04-17 13:23:39 +00:00
menu_ref = ctx and ctx . get ( ' needaction_menu_ref ' )
if menu_ref :
if not isinstance ( menu_ref , list ) :
menu_ref = [ menu_ref ]
model_data_obj = self . pool . get ( ' ir.model.data ' )
for menu_data in menu_ref :
2014-05-20 11:30:15 +00:00
try :
model , id = model_data_obj . get_object_reference ( cr , uid , menu_data . split ( ' . ' ) [ 0 ] , menu_data . split ( ' . ' ) [ 1 ] )
if ( model == ' ir.ui.menu ' ) :
menu_ids . add ( id )
except Exception :
pass
2013-04-25 14:28:01 +00:00
menu_ids = list ( menu_ids )
2013-04-17 13:23:39 +00:00
for menu in self . browse ( cr , uid , menu_ids , context = context ) :
2012-08-28 07:53:21 +00:00
res [ menu . id ] = {
' needaction_enabled ' : False ,
' needaction_counter ' : False ,
}
2012-12-05 10:20:52 +00:00
if menu . action and menu . action . type in ( ' ir.actions.act_window ' , ' ir.actions.client ' ) and menu . action . res_model :
2013-03-29 14:07:23 +00:00
if menu . action . res_model in self . pool :
obj = self . pool [ menu . action . res_model ]
if obj . _needaction :
if menu . action . type == ' ir.actions.act_window ' :
dom = menu . action . domain and eval ( menu . action . domain , { ' uid ' : uid } ) or [ ]
else :
dom = eval ( menu . action . params_store or ' {} ' , { ' uid ' : uid } ) . get ( ' domain ' )
res [ menu . id ] [ ' needaction_enabled ' ] = obj . _needaction
res [ menu . id ] [ ' needaction_counter ' ] = obj . _needaction_count ( cr , uid , dom , context = context )
2012-03-28 16:35:49 +00:00
return res
2012-08-19 14:59:28 +00:00
2014-06-27 09:03:34 +00:00
def get_user_roots ( self , cr , uid , context = None ) :
""" Return all root menu ids visible for the user.
: return : the root menu ids
: rtype : list ( int )
"""
menu_domain = [ ( ' parent_id ' , ' = ' , False ) ]
return self . search ( cr , uid , menu_domain , context = context )
2014-07-17 15:18:14 +00:00
@api.cr_uid_context
@tools.ormcache_context ( accepted_keys = ( ' lang ' , ) )
2014-06-30 17:45:12 +00:00
def load_menus_root ( self , cr , uid , context = None ) :
fields = [ ' name ' , ' sequence ' , ' parent_id ' , ' action ' ]
menu_root_ids = self . get_user_roots ( cr , uid , context = context )
menu_roots = self . read ( cr , uid , menu_root_ids , fields , context = context ) if menu_root_ids else [ ]
return {
' id ' : False ,
' name ' : ' root ' ,
' parent_id ' : [ - 1 , ' ' ] ,
' children ' : menu_roots ,
' all_menu_ids ' : menu_root_ids ,
}
2014-07-17 15:18:14 +00:00
@api.cr_uid_context
@tools.ormcache_context ( accepted_keys = ( ' lang ' , ) )
2014-06-27 09:03:34 +00:00
def load_menus ( self , cr , uid , context = None ) :
""" Loads all menu items (all applications and their sub-menus).
: return : the menu root
: rtype : dict ( ' children ' : menu_nodes )
"""
fields = [ ' name ' , ' sequence ' , ' parent_id ' , ' action ' ]
menu_root_ids = self . get_user_roots ( cr , uid , context = context )
menu_roots = self . read ( cr , uid , menu_root_ids , fields , context = context ) if menu_root_ids else [ ]
menu_root = {
' id ' : False ,
' name ' : ' root ' ,
' parent_id ' : [ - 1 , ' ' ] ,
' children ' : menu_roots ,
' all_menu_ids ' : menu_root_ids ,
}
if not menu_roots :
return menu_root
# menus are loaded fully unlike a regular tree view, cause there are a
# limited number of items (752 when all 6.1 addons are installed)
menu_ids = self . search ( cr , uid , [ ( ' id ' , ' child_of ' , menu_root_ids ) ] , 0 , False , False , context = context )
menu_items = self . read ( cr , uid , menu_ids , fields , context = context )
# adds roots at the end of the sequence, so that they will overwrite
# equivalent menu items from full menu read when put into id:item
# mapping, resulting in children being correctly set on the roots.
menu_items . extend ( menu_roots )
menu_root [ ' all_menu_ids ' ] = menu_ids # includes menu_root_ids!
# make a tree using parent_id
menu_items_map = dict (
( menu_item [ " id " ] , menu_item ) for menu_item in menu_items )
for menu_item in menu_items :
if menu_item [ ' parent_id ' ] :
parent = menu_item [ ' parent_id ' ] [ 0 ]
else :
parent = False
if parent in menu_items_map :
menu_items_map [ parent ] . setdefault (
' children ' , [ ] ) . append ( menu_item )
# sort by sequence a tree using parent_id
for menu_item in menu_items :
menu_item . setdefault ( ' children ' , [ ] ) . sort (
key = operator . itemgetter ( ' sequence ' ) )
return menu_root
2008-07-22 14:24:36 +00:00
_columns = {
2014-05-21 09:52:05 +00:00
' name ' : fields . char ( ' Menu ' , required = True , translate = True ) ,
2008-07-22 14:24:36 +00:00
' sequence ' : fields . integer ( ' Sequence ' ) ,
2012-12-05 10:20:52 +00:00
' child_id ' : fields . one2many ( ' ir.ui.menu ' , ' parent_id ' , ' Child IDs ' ) ,
2012-12-12 21:04:51 +00:00
' parent_id ' : fields . many2one ( ' ir.ui.menu ' , ' Parent Menu ' , select = True , ondelete = " restrict " ) ,
' parent_left ' : fields . integer ( ' Parent Left ' , select = True ) ,
' parent_right ' : fields . integer ( ' Parent Right ' , 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. " \
2014-07-09 11:39:38 +00:00
" If this field is empty, Odoo will compute visibility based on the related object ' s read access. " ) ,
2012-10-29 10:46:36 +00:00
' complete_name ' : fields . function ( _get_full_name ,
2012-06-04 18:30:55 +00:00
string = ' Full Path ' , type = ' char ' , size = 128 ) ,
2008-09-16 12:26:07 +00:00
' icon ' : fields . selection ( tools . icons , ' Icon ' , size = 64 ) ,
2012-01-04 13:30:27 +00:00
' icon_pict ' : fields . function ( _get_icon_pict , type = ' char ' , size = 32 ) ,
2014-05-21 09:52:05 +00:00
' web_icon ' : fields . char ( ' Web Icon File ' ) ,
' web_icon_hover ' : fields . char ( ' Web Icon File (hover) ' ) ,
2012-01-04 13:30:27 +00:00
' web_icon_data ' : fields . function ( _get_image_icon , string = ' Web Icon Image ' , type = ' binary ' , readonly = True , store = True , multi = ' icon ' ) ,
2012-12-05 10:20:52 +00:00
' web_icon_hover_data ' : fields . function ( _get_image_icon , string = ' Web Icon Image (hover) ' , type = ' binary ' , readonly = True , store = True , multi = ' icon ' ) ,
' needaction_enabled ' : fields . function ( _get_needaction_enabled ,
type = ' boolean ' ,
store = True ,
string = ' Target model uses the need action mechanism ' ,
help = ' If the menu entry action is an act_window action, and if this action is related to a model that uses the need_action mechanism, this field is set to true. Otherwise, it is false. ' ) ,
2008-07-22 14:24:36 +00:00
' action ' : fields . function ( _action , fnct_inv = _action_inv ,
2014-05-21 09:52:05 +00:00
type = ' reference ' , string = ' Action ' , size = 21 ,
2008-07-22 14:24:36 +00:00
selection = [
( ' ir.actions.report.xml ' , ' ir.actions.report.xml ' ) ,
( ' ir.actions.act_window ' , ' ir.actions.act_window ' ) ,
( ' ir.actions.wizard ' , ' ir.actions.wizard ' ) ,
2012-06-08 10:17:10 +00:00
( ' ir.actions.act_url ' , ' ir.actions.act_url ' ) ,
2010-02-04 17:24:36 +00:00
( ' ir.actions.server ' , ' ir.actions.server ' ) ,
2011-07-01 13:05:17 +00:00
( ' ir.actions.client ' , ' ir.actions.client ' ) ,
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 = [
2012-12-05 10:20:52 +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 = {
2012-12-05 10:20:52 +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 "
2012-12-12 21:04:51 +00:00
_parent_store = True
2008-07-23 15:01:27 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: