diff options
| author | Olivier Dony <odo@openerp.com> | 2012-05-18 12:07:06 +0200 |
|---|---|---|
| committer | Olivier Dony <odo@openerp.com> | 2012-05-18 12:07:06 +0200 |
| commit | f28bdc7c9be9d9391c08e5699b66fa64c6d4e5ee (patch) | |
| tree | 60554c94b8558473eb3fe35dbd5b10d9b2d37649 | |
| parent | bd0bc7d4c53d96b005603e25b45ad82b22221fba (diff) | |
| parent | 2f9888a7016df56ecfabd88341fa942073f55f9b (diff) | |
[MERGE] ir.filters: unassigned filters are now global
Both clients will be adapted very soon to properly
handle the new global filters
bzr revid: odo@openerp.com-20120518100706-n5o94okkf119grky
| -rw-r--r-- | openerp/addons/base/__openerp__.py | 1 | ||||
| -rw-r--r-- | openerp/addons/base/ir/ir.xml | 75 | ||||
| -rw-r--r-- | openerp/addons/base/ir/ir_filters.py | 46 | ||||
| -rw-r--r-- | openerp/addons/base/ir/ir_filters.xml | 79 |
4 files changed, 116 insertions, 85 deletions
diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index 862482736a0..75c809d7046 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -41,6 +41,7 @@ 'update_xml': [ 'ir/wizard/wizard_menu_view.xml', 'ir/ir.xml', + 'ir/ir_filters.xml', 'ir/ir_config_parameter_view.xml', 'ir/workflow/workflow_view.xml', 'ir/report/ir_report.xml', diff --git a/openerp/addons/base/ir/ir.xml b/openerp/addons/base/ir/ir.xml index b48279e1027..837374d371b 100644 --- a/openerp/addons/base/ir/ir.xml +++ b/openerp/addons/base/ir/ir.xml @@ -322,78 +322,7 @@ <menuitem action="act_values_form_action" id="menu_values_form_action" parent="next_id_6"/> <menuitem action="act_values_form_defaults" id="menu_values_form_defaults" parent="next_id_6"/> - <!--Filters form view--> - <record id="ir_filters_view_form" model="ir.ui.view"> - <field name="name">ir.filters.form</field> - <field name="model">ir.filters</field> - <field name="type">form</field> - <field name="arch" type="xml"> - <form string="Filters"> - <group colspan="4" col="6" > - <field name="name"/> - <field name="model_id"/> - <field name="user_id"/> - </group> - <group col="4" expand="1"> - <separator string="Domain" colspan="2" /> - <separator string="Context" colspan="2" /> - <field name="domain" nolabel="1" colspan="2"/> - <field name="context" nolabel="1" colspan="2"/> - </group> - </form> - </field> - </record> - - <!-- Filters tree view--> - - <record id="ir_filters_view_tree" model="ir.ui.view"> - <field name="name">ir.filters.tree</field> - <field name="model">ir.filters</field> - <field name="type">tree</field> - <field name="arch" type="xml"> - <tree string="Filters"> - <field name="name"/> - <field name="model_id"/> - <field name="user_id"/> - <field name="domain" groups="base.group_no_one"/> - <field name="context" groups="base.group_no_one"/> - </tree> - </field> - </record> - - <!--Filters search view--> - - <record id="ir_filters_view_search" model="ir.ui.view"> - <field name="name">ir.filters.search</field> - <field name="model">ir.filters</field> - <field name="type">search</field> - <field name="arch" type="xml"> - <search string="Filters"> - <field name="name"/> - <field name="model_id"/> - <field name="user_id"> - <filter icon="terp-personal" domain="[('user_id','in', (uid, False))]" help="Current User" name="My Filters" /> - </field> - </search> - </field> - </record> - - <!-- Filters action--> - - <record id="actions_ir_filters_view" model="ir.actions.act_window"> - <field name="name">Filters</field> - <field name="type">ir.actions.act_window</field> - <field name="res_model">ir.filters</field> - <field name="view_type">form</field> - <field name="view_id" ref="ir_filters_view_tree"/> - <field name="search_view_id" ref="ir_filters_view_search"/> - </record> - - <!-- Filters view menu--> - - <menuitem parent="base.next_id_6" name="Filters" - id="menu_ir_filters" action="actions_ir_filters_view" /> <record id="act_report_xml_view" model="ir.ui.view"> <field name="name">ir.actions.report.xml</field> @@ -768,7 +697,7 @@ <field name="view_id" ref="view_view_tree"/> <field name="help">Views allows you to personalize each view of OpenERP. You can add new fields, move fields, rename them or delete the ones that you do not need.</field> </record> - <menuitem action="action_ui_view" id="menu_action_ui_view" parent="base.next_id_2"/> + <menuitem action="action_ui_view" id="menu_action_ui_view" parent="base.next_id_2" sequence="2"/> <!-- View customizations --> @@ -813,7 +742,7 @@ <field name="res_model">ir.ui.view.custom</field> <field name="help">Customized views are used when users reorganize the content of their dashboard views (via web client)</field> </record> - <menuitem id="menu_action_ui_view_custom" action="action_ui_view_custom" parent="base.next_id_2"/> + <menuitem id="menu_action_ui_view_custom" action="action_ui_view_custom" parent="base.next_id_2" sequence="3"/> <!-- Attachment --> diff --git a/openerp/addons/base/ir/ir_filters.py b/openerp/addons/base/ir/ir_filters.py index 19b26768b10..02a723c116c 100644 --- a/openerp/addons/base/ir/ir_filters.py +++ b/openerp/addons/base/ir/ir_filters.py @@ -37,39 +37,61 @@ class ir_filters(osv.osv): name = self.read(cr, uid, [id], ['name'])[0]['name'] default.update({'name':_('%s (copy)') % name}) return super(ir_filters, self).copy(cr, uid, id, default, context) - + def get_filters(self, cr, uid, model): - act_ids = self.search(cr,uid,[('model_id','=',model),('user_id','=',uid)]) - my_acts = self.read(cr, uid, act_ids, ['name', 'domain','context']) + """Obtain the list of filters available for the user on the given model. + + :return: list of :meth:`~osv.read`-like dicts containing the ``name``, + ``domain``, ``user_id`` (m2o tuple) and ``context`` of the matching ``ir.filters``. + """ + # available filters: private filters (user_id=uid) and public filters (uid=NULL) + act_ids = self.search(cr, uid, [('model_id','=',model),('user_id','in',[uid, False])]) + my_acts = self.read(cr, uid, act_ids, ['name', 'domain', 'context', 'user_id']) return my_acts def create_or_replace(self, cr, uid, vals, context=None): - filter_id = None lower_name = vals['name'].lower() - matching_filters = [x for x in self.get_filters(cr, uid, vals['model_id']) - if x['name'].lower() == lower_name] + matching_filters = [f for f in self.get_filters(cr, uid, vals['model_id']) + if f['name'].lower() == lower_name + # next line looks for matching user_ids (specific or global), i.e. + # f.user_id is False and vals.user_id is False or missing, + # or f.user_id.id == vals.user_id + if (f['user_id'] and f['user_id'][0]) == vals.get('user_id', False)] + # When a filter exists for the same (name, model, user) triple, we simply + # replace its definition. if matching_filters: self.write(cr, uid, matching_filters[0]['id'], vals, context) - return False + return matching_filters[0]['id'] return self.create(cr, uid, vals, context) + _sql_constraints = [ + # Partial constraint, complemented by unique index (see below) + # Still useful to keep because it provides a proper error message when a violation + # occurs, as it shares the same prefix as the unique index. + ('name_model_uid_unique', 'unique (name, model_id, user_id)', 'Filter names must be unique'), + ] + def _auto_init(self, cr, context=None): super(ir_filters, self)._auto_init(cr, context) # Use unique index to implement unique constraint on the lowercase name (not possible using a constraint) cr.execute("SELECT indexname FROM pg_indexes WHERE indexname = 'ir_filters_name_model_uid_unique_index'") if not cr.fetchone(): - cr.execute('CREATE UNIQUE INDEX "ir_filters_name_model_uid_unique_index" ON ir_filters (lower(name), model_id, user_id)') + cr.execute("""CREATE UNIQUE INDEX "ir_filters_name_model_uid_unique_index" ON ir_filters + (lower(name), model_id, COALESCE(user_id,-1))""") _columns = { 'name': fields.char('Filter Name', size=64, translate=True, required=True), - 'user_id':fields.many2one('res.users', 'User', help="The user this filter is available to. When left empty the filter is usable by the system only."), - 'domain': fields.text('Domain Value', required=True), - 'context': fields.text('Context Value', required=True), - 'model_id': fields.selection(_list_all_models, 'Object', size=64, required=True), + 'user_id': fields.many2one('res.users', 'User', ondelete='cascade', + help="The user this filter is private to. When left empty the filter is public " + "and available to all users."), + 'domain': fields.text('Domain', required=True), + 'context': fields.text('Context', required=True), + 'model_id': fields.selection(_list_all_models, 'Model', required=True), } _defaults = { 'domain': '[]', 'context':'{}', + 'user_id': lambda self,cr,uid,context=None: uid, } ir_filters() diff --git a/openerp/addons/base/ir/ir_filters.xml b/openerp/addons/base/ir/ir_filters.xml new file mode 100644 index 00000000000..a0e37b45e5a --- /dev/null +++ b/openerp/addons/base/ir/ir_filters.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="utf-8"?> +<openerp> + + <data noupdate="1"> + <!-- Restrict modifications on ir.filters to owner only --> + <record id="ir_filters_rule" model="ir.rule"> + <field name="name">ir.filters.owner</field> + <field model="ir.model" name="model_id" ref="model_ir_filters"/> + <field name="domain_force">[('user_id','in',[False,user.id])]</field> + </record> + </data> + + <data> + <record id="ir_filters_view_form" model="ir.ui.view"> + <field name="name">ir.filters.form</field> + <field name="model">ir.filters</field> + <field name="type">form</field> + <field name="arch" type="xml"> + <form string="Filters"> + <group colspan="4" col="6" > + <field name="name"/> + <field name="model_id"/> + <field name="user_id"/> + </group> + <group col="4" expand="1"> + <separator string="Domain" colspan="2" /> + <separator string="Context" colspan="2" /> + <field name="domain" nolabel="1" colspan="2"/> + <field name="context" nolabel="1" colspan="2"/> + </group> + </form> + </field> + </record> + + <record id="ir_filters_view_tree" model="ir.ui.view"> + <field name="name">ir.filters.tree</field> + <field name="model">ir.filters</field> + <field name="type">tree</field> + <field name="arch" type="xml"> + <tree string="Filters"> + <field name="name"/> + <field name="model_id"/> + <field name="user_id"/> + <field name="domain" groups="base.group_no_one"/> + <field name="context" groups="base.group_no_one"/> + </tree> + </field> + </record> + + <record id="ir_filters_view_search" model="ir.ui.view"> + <field name="name">ir.filters.search</field> + <field name="model">ir.filters</field> + <field name="type">search</field> + <field name="arch" type="xml"> + <search string="Filters"> + <filter string="Personal" domain="[('user_id','!=',False)]" help="Filters visible only for one user"/> + <filter string="Shared" domain="[('user_id','=',False)]" help="Filters shared with all users"/> + <separator orientation="vertical"/> + <field name="name"/> + <field name="model_id"/> + <field name="user_id"> + <filter icon="terp-personal" domain="[('user_id','in',(uid, False))]" + name="my_filters" + string="My Filters" /> + </field> + </search> + </field> + </record> + + <record id="actions_ir_filters_view" model="ir.actions.act_window"> + <field name="name">Filters</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">ir.filters</field> + </record> + + <menuitem parent="base.next_id_2" name="User-defined Filters" + id="menu_ir_filters" action="actions_ir_filters_view" sequence="5"/> + </data> +</openerp>
\ No newline at end of file |
