@@ -36,15 +36,30 @@ def copy(self, cr, uid, id, default=None, context=None):
36
36
default .update ({'name' :_ ('%s (copy)' ) % name })
37
37
return super (ir_filters , self ).copy (cr , uid , id , default , context )
38
38
39
- def get_filters (self , cr , uid , model ):
39
+ def _get_action_domain (self , cr , uid , action_id = None ):
40
+ """Return a domain component for matching filters that are visible in the
41
+ same context (menu/view) as the given action."""
42
+ if action_id :
43
+ # filters specific to this menu + global ones
44
+ return [('action_id' , 'in' , [action_id , False ])]
45
+ # only global ones
46
+ return [('action_id' , '=' , False )]
47
+
48
+ def get_filters (self , cr , uid , model , action_id = None ):
40
49
"""Obtain the list of filters available for the user on the given model.
41
50
51
+ :param action_id: optional ID of action to restrict filters to this action
52
+ plus global filters. If missing only global filters are returned.
53
+ The action does not have to correspond to the model, it may only be
54
+ a contextual action.
42
55
:return: list of :meth:`~osv.read`-like dicts containing the
43
- ``name``, ``is_default``, ``domain``, ``user_id`` (m2o tuple) and
44
- ``context`` of the matching ``ir.filters``.
56
+ ``name``, ``is_default``, ``domain``, ``user_id`` (m2o tuple),
57
+ ``action_id`` (m2o tuple) and `` context`` of the matching ``ir.filters``.
45
58
"""
46
- # available filters: private filters (user_id=uid) and public filters (uid=NULL)
47
- filter_ids = self .search (cr , uid ,
59
+ # available filters: private filters (user_id=uid) and public filters (uid=NULL),
60
+ # and filters for the action (action_id=action_id) or global (action_id=NULL)
61
+ action_domain = self ._get_action_domain (cr , uid , action_id )
62
+ filter_ids = self .search (cr , uid , action_domain +
48
63
[('model_id' ,'=' ,model ),('user_id' ,'in' ,[uid , False ])])
49
64
my_filters = self .read (cr , uid , filter_ids ,
50
65
['name' , 'is_default' , 'domain' , 'context' , 'user_id' ])
@@ -66,7 +81,8 @@ def _check_global_default(self, cr, uid, vals, matching_filters, context=None):
66
81
:raises openerp.exceptions.Warning: if there is an existing default and
67
82
we're not updating it
68
83
"""
69
- existing_default = self .search (cr , uid , [
84
+ action_domain = self ._get_action_domain (cr , uid , vals .get ('action_id' ))
85
+ existing_default = self .search (cr , uid , action_domain + [
70
86
('model_id' , '=' , vals ['model_id' ]),
71
87
('user_id' , '=' , False ),
72
88
('is_default' , '=' , True )], context = context )
@@ -83,7 +99,9 @@ def _check_global_default(self, cr, uid, vals, matching_filters, context=None):
83
99
84
100
def create_or_replace (self , cr , uid , vals , context = None ):
85
101
lower_name = vals ['name' ].lower ()
86
- matching_filters = [f for f in self .get_filters (cr , uid , vals ['model_id' ])
102
+ action_id = vals .get ('action_id' )
103
+ current_filters = self .get_filters (cr , uid , vals ['model_id' ], action_id )
104
+ matching_filters = [f for f in current_filters
87
105
if f ['name' ].lower () == lower_name
88
106
# next line looks for matching user_ids (specific or global), i.e.
89
107
# f.user_id is False and vals.user_id is False or missing,
@@ -92,18 +110,22 @@ def create_or_replace(self, cr, uid, vals, context=None):
92
110
93
111
if vals .get ('is_default' ):
94
112
if vals .get ('user_id' ):
95
- act_ids = self .search (cr , uid , [
113
+ # Setting new default: any other default that belongs to the user
114
+ # should be turned off
115
+ action_domain = self ._get_action_domain (cr , uid , action_id )
116
+ act_ids = self .search (cr , uid , action_domain + [
96
117
('model_id' , '=' , vals ['model_id' ]),
97
118
('user_id' , '=' , vals ['user_id' ]),
98
119
('is_default' , '=' , True ),
99
120
], context = context )
100
- self .write (cr , uid , act_ids , {'is_default' : False }, context = context )
121
+ if act_ids :
122
+ self .write (cr , uid , act_ids , {'is_default' : False }, context = context )
101
123
else :
102
124
self ._check_global_default (
103
125
cr , uid , vals , matching_filters , context = None )
104
126
105
127
# When a filter exists for the same (name, model, user) triple, we simply
106
- # replace its definition.
128
+ # replace its definition (considering action_id irrelevant here)
107
129
if matching_filters :
108
130
self .write (cr , uid , matching_filters [0 ]['id' ], vals , context )
109
131
return matching_filters [0 ]['id' ]
@@ -114,16 +136,17 @@ def create_or_replace(self, cr, uid, vals, context=None):
114
136
# Partial constraint, complemented by unique index (see below)
115
137
# Still useful to keep because it provides a proper error message when a violation
116
138
# occurs, as it shares the same prefix as the unique index.
117
- ('name_model_uid_unique' , 'unique (name, model_id, user_id)' , 'Filter names must be unique' ),
139
+ ('name_model_uid_unique' , 'unique (name, model_id, user_id, action_id )' , 'Filter names must be unique' ),
118
140
]
119
141
120
142
def _auto_init (self , cr , context = None ):
121
143
super (ir_filters , self )._auto_init (cr , context )
122
144
# Use unique index to implement unique constraint on the lowercase name (not possible using a constraint)
123
- cr .execute ("SELECT indexname FROM pg_indexes WHERE indexname = 'ir_filters_name_model_uid_unique_index'" )
145
+ cr .execute ("DROP INDEX IF EXISTS ir_filters_name_model_uid_unique_index" ) # drop old index w/o action
146
+ cr .execute ("SELECT indexname FROM pg_indexes WHERE indexname = 'ir_filters_name_model_uid_unique_action_index'" )
124
147
if not cr .fetchone ():
125
- cr .execute ("""CREATE UNIQUE INDEX "ir_filters_name_model_uid_unique_index " ON ir_filters
126
- (lower(name), model_id, COALESCE(user_id,-1))""" )
148
+ cr .execute ("""CREATE UNIQUE INDEX "ir_filters_name_model_uid_unique_action_index " ON ir_filters
149
+ (lower(name), model_id, COALESCE(user_id,-1), COALESCE(action_id,-1) )""" )
127
150
128
151
_columns = {
129
152
'name' : fields .char ('Filter Name' , translate = True , required = True ),
@@ -133,13 +156,18 @@ def _auto_init(self, cr, context=None):
133
156
'domain' : fields .text ('Domain' , required = True ),
134
157
'context' : fields .text ('Context' , required = True ),
135
158
'model_id' : fields .selection (_list_all_models , 'Model' , required = True ),
136
- 'is_default' : fields .boolean ('Default filter' )
159
+ 'is_default' : fields .boolean ('Default filter' ),
160
+ 'action_id' : fields .many2one ('ir.actions.actions' , 'Action' , ondelete = 'cascade' ,
161
+ help = "The menu action this filter applies to. "
162
+ "When left empty the filter applies to all menus "
163
+ "for this model." )
137
164
}
138
165
_defaults = {
139
166
'domain' : '[]' ,
140
167
'context' :'{}' ,
141
168
'user_id' : lambda self ,cr ,uid ,context = None : uid ,
142
169
'is_default' : False
143
170
}
171
+ _order = 'model_id, name, id desc'
144
172
145
173
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
0 commit comments