[FIX] base: deleting a view must not delete linked actions
[odoo/odoo.git] / openerp / addons / base / ir / ir_actions.py
index d745174..9112fc4 100644 (file)
@@ -31,6 +31,7 @@ import openerp
 from openerp import SUPERUSER_ID
 from openerp import tools
 from openerp import workflow
+import openerp.api
 from openerp.osv import fields, osv
 from openerp.osv.orm import browse_record
 import openerp.report.interface
@@ -41,14 +42,15 @@ import openerp.workflow
 
 _logger = logging.getLogger(__name__)
 
+
 class actions(osv.osv):
     _name = 'ir.actions.actions'
     _table = 'ir_actions'
     _order = 'name'
     _columns = {
-        'name': fields.char('Name', size=64, required=True),
-        'type': fields.char('Action Type', required=True, size=32),
-        'usage': fields.char('Action Usage', size=32),
+        'name': fields.char('Name', required=True),
+        'type': fields.char('Action Type', required=True),
+        'usage': fields.char('Action Usage'),
         'help': fields.text('Action description',
             help='Optional help text for the users with a description of the target view, such as its usage and purpose.',
             translate=True),
@@ -57,6 +59,17 @@ class actions(osv.osv):
         'usage': lambda *a: False,
     }
 
+    def unlink(self, cr, uid, ids, context=None):
+        """unlink ir.action.todo which are related to actions which will be deleted.
+           NOTE: ondelete cascade will not work on ir.actions.actions so we will need to do it manually."""
+        todo_obj = self.pool.get('ir.actions.todo')
+        if not ids:
+            return True
+        if isinstance(ids, (int, long)):
+            ids = [ids]
+        todo_ids = todo_obj.search(cr, uid, [('action_id', 'in', ids)], context=context)
+        todo_obj.unlink(cr, uid, todo_ids, context=context)
+        return super(actions, self).unlink(cr, uid, ids, context=context)
 
 class ir_actions_report_xml(osv.osv):
 
@@ -104,7 +117,9 @@ class ir_actions_report_xml(osv.osv):
             cr.execute("SELECT * FROM ir_act_report_xml WHERE report_name=%s", (name,))
             r = cr.dictfetchone()
             if r:
-                if r['report_rml'] or r['report_rml_content_data']:
+                if r['report_type'] in ['qweb-pdf', 'qweb-html']:
+                    return r['report_name']
+                elif r['report_rml'] or r['report_rml_content_data']:
                     if r['parser']:
                         kwargs = { 'parser': operator.attrgetter(r['parser'])(openerp.addons) }
                     else:
@@ -118,7 +133,7 @@ class ir_actions_report_xml(osv.osv):
                 else:
                     raise Exception, "Unhandled report type: %s" % r
             else:
-                raise Exception, "Required report does not exist: %s" % r
+                raise Exception, "Required report does not exist: %s" % name
 
         return new_report
 
@@ -127,7 +142,17 @@ class ir_actions_report_xml(osv.osv):
         Look up a report definition and render the report for the provided IDs.
         """
         new_report = self._lookup_report(cr, name)
-        return new_report.create(cr, uid, res_ids, data, context)
+
+        if isinstance(new_report, (str, unicode)):  # Qweb report
+            # The only case where a QWeb report is rendered with this method occurs when running
+            # yml tests originally written for RML reports.
+            if openerp.tools.config['test_enable'] and not tools.config['test_report_directory']:
+                # Only generate the pdf when a destination folder has been provided.
+                return self.pool['report'].get_html(cr, uid, res_ids, new_report, data=data, context=context), 'html'
+            else:
+                return self.pool['report'].get_pdf(cr, uid, res_ids, new_report, data=data, context=context), 'pdf'
+        else:
+            return new_report.create(cr, uid, res_ids, data, context)
 
     _name = 'ir.actions.report.xml'
     _inherit = 'ir.actions.actions'
@@ -135,27 +160,27 @@ class ir_actions_report_xml(osv.osv):
     _sequence = 'ir_actions_id_seq'
     _order = 'name'
     _columns = {
-        'type': fields.char('Action Type', size=32, required=True),
-        'name': fields.char('Name', size=64, required=True, translate=True),
+        'type': fields.char('Action Type', required=True),
+        'name': fields.char('Name', required=True, translate=True),
 
         'model': fields.char('Model', required=True),
         'report_type': fields.selection([('qweb-pdf', 'PDF'),
                     ('qweb-html', 'HTML'),
-                    ('other', 'Other'),
+                    ('controller', 'Controller'),
                     ('pdf', 'RML pdf (deprecated)'),
                     ('sxw', 'RML sxw (deprecated)'),
                     ('webkit', 'Webkit (deprecated)'),
-                    ], 'Report Type', required=True, help="PDF will use wkhtmltopdf to render html to pdf, HTML will directly show html, Other will force download the controller output keeping the MIME type."),
-        'report_name': fields.char('Controller Name', required=True, help="URL of the report will be /report/<controller name>/<ids>, the default controller also use this field to get the name of the qweb ir.ui.view to render. For RML reports, this is the LocalService name."),
+                    ], 'Report Type', required=True, help="HTML will open the report directly in your browser, PDF will use wkhtmltopdf to render the HTML into a PDF file and let you download it, Controller allows you to define the url of a custom controller outputting any kind of report."),
+        'report_name': fields.char('Template Name', required=True, help="For QWeb reports, name of the template used in the rendering. The method 'render_html' of the model 'report.template_name' will be called (if any) to give the html. For RML reports, this is the LocalService name."),
         'groups_id': fields.many2many('res.groups', 'res_groups_report_rel', 'uid', 'gid', 'Groups'),
 
         # options
         'multi': fields.boolean('On Multiple Doc.', help="If set to true, the action will not be displayed on the right toolbar of a form view."),
         'attachment_use': fields.boolean('Reload from Attachment', help='If you check this, then the second time the user prints with same attachment name, it returns the previous report.'),
-        'attachment': fields.char('Save as Attachment Prefix', size=128, help='This is the filename of the attachment used to store the printing result. Keep empty to not save the printed reports. You can use a python expression with the object and time variables.'),
+        'attachment': fields.char('Save as Attachment Prefix', help='This is the filename of the attachment used to store the printing result. Keep empty to not save the printed reports. You can use a python expression with the object and time variables.'),
 
         # Deprecated rml stuff
-        'usage': fields.char('Action Usage', size=32),
+        'usage': fields.char('Action Usage'),
         'header': fields.boolean('Add RML Header', help="Add or not the corporate RML header"),
         'parser': fields.char('Parser Class'),
         'auto': fields.boolean('Custom Python Parser'),
@@ -163,7 +188,7 @@ class ir_actions_report_xml(osv.osv):
         'report_xsl': fields.char('XSL Path'),
         'report_xml': fields.char('XML Path'),
 
-        'report_rml': fields.char('Main Report File Path', help="The path to the main report file (depending on Report Type) or NULL if the content is in another data field"),
+        'report_rml': fields.char('Main Report File Path/controller', help="The path to the main report file/controller (depending on Report Type) or NULL if the content is in another data field"),
         'report_file': fields.related('report_rml', type="char", required=False, readonly=False, string='Report File', help="The path to the main report file (depending on Report Type) or NULL if the content is in another field", store=True),
 
         'report_sxw': fields.function(_report_sxw, type='char', string='SXW Path'),
@@ -244,24 +269,24 @@ class ir_actions_act_window(osv.osv):
         return res
 
     _columns = {
-        'name': fields.char('Action Name', size=64, translate=True),
-        'type': fields.char('Action Type', size=32, required=True),
-        'view_id': fields.many2one('ir.ui.view', 'View Ref.', ondelete='cascade'),
+        'name': fields.char('Action Name', translate=True),
+        'type': fields.char('Action Type', required=True),
+        'view_id': fields.many2one('ir.ui.view', 'View Ref.', ondelete='set null'),
         'domain': fields.char('Domain Value',
             help="Optional domain filtering of the destination data, as a Python expression"),
         'context': fields.char('Context Value', required=True,
             help="Context dictionary as Python expression, empty by default (Default: {})"),
         'res_id': fields.integer('Record ID', help="Database ID of record to open in form view, when ``view_mode`` is set to 'form' only"),
-        'res_model': fields.char('Destination Model', size=64, required=True,
+        'res_model': fields.char('Destination Model', required=True,
             help="Model name of the object to open in the view window"),
-        'src_model': fields.char('Source Model', size=64,
+        'src_model': fields.char('Source Model',
             help="Optional model name of the objects on which this action should be visible"),
         'target': fields.selection([('current','Current Window'),('new','New Window'),('inline','Inline Edit'),('inlineview','Inline View')], 'Target Window'),
-        'view_mode': fields.char('View Mode', size=250, required=True,
+        'view_mode': fields.char('View Mode', required=True,
             help="Comma-separated list of allowed view modes, such as 'form', 'tree', 'calendar', etc. (Default: tree,form)"),
         'view_type': fields.selection((('tree','Tree'),('form','Form')), string='View Type', required=True,
             help="View type: Tree type to use for the tree view, set to 'tree' for a hierarchical tree view, or 'form' for a regular list view"),
-        'usage': fields.char('Action Usage', size=32,
+        'usage': fields.char('Action Usage',
             help="Used to filter menu and home actions from the user form."),
         'view_ids': fields.one2many('ir.actions.act_window.view', 'act_window_id', 'Views'),
         'views': fields.function(_views_get_fnc, type='binary', string='Views',
@@ -300,24 +325,26 @@ class ir_actions_act_window(osv.osv):
             ids = [ids]
         results = super(ir_actions_act_window, self).read(cr, uid, ids, fields=fields, context=context, load=load)
 
-        if not fields or 'help' in fields:
-            context = dict(context or {})
-            eval_dict = {
-                'active_model': context.get('active_model'),
-                'active_id': context.get('active_id'),
-                'active_ids': context.get('active_ids'),
-                'uid': uid,
-            }
-            for res in results:
-                model = res.get('res_model')
-                if model and self.pool.get(model):
-                    try:
-                        with tools.mute_logger("openerp.tools.safe_eval"):
-                            eval_context = eval(res['context'] or "{}", eval_dict) or {}
-                    except Exception:
-                        continue
+        context = dict(context or {})
+        eval_dict = {
+            'active_model': context.get('active_model'),
+            'active_id': context.get('active_id'),
+            'active_ids': context.get('active_ids'),
+            'uid': uid,
+            'context': context,
+        }
+        for res in results:
+            model = res.get('res_model')
+            if model in self.pool:
+                try:
+                    with tools.mute_logger("openerp.tools.safe_eval"):
+                        eval_context = eval(res['context'] or "{}", eval_dict) or {}
+                        res['context'] = str(eval_context)
+                except Exception:
+                    continue
+                if not fields or 'help' in fields:
                     custom_context = dict(context, **eval_context)
-                    res['help'] = self.pool.get(model).get_empty_list_help(cr, uid, res.get('help', ""), context=custom_context)
+                    res['help'] = self.pool[model].get_empty_list_help(cr, uid, res.get('help', ""), context=custom_context)
         if ids_int:
             return results[0]
         return results
@@ -333,7 +360,7 @@ class ir_actions_act_window(osv.osv):
         dataobj = self.pool.get('ir.model.data')
         data_id = dataobj._get_id (cr, SUPERUSER_ID, module, xml_id)
         res_id = dataobj.browse(cr, uid, data_id, context).res_id
-        return self.read(cr, uid, res_id, [], context)
+        return self.read(cr, uid, [res_id], [], context)[0]
 
 VIEW_TYPES = [
     ('tree', 'Tree'),
@@ -381,8 +408,8 @@ class ir_actions_act_url(osv.osv):
     _sequence = 'ir_actions_id_seq'
     _order = 'name'
     _columns = {
-        'name': fields.char('Action Name', size=64, translate=True),
-        'type': fields.char('Action Type', size=32, required=True),
+        'name': fields.char('Action Name', translate=True),
+        'type': fields.char('Action Type', required=True),
         'url': fields.text('Action URL',required=True),
         'target': fields.selection((
             ('new', 'New Window'),
@@ -445,7 +472,7 @@ class ir_actions_server(osv.osv):
         return self._get_states(cr, uid, context)
 
     _columns = {
-        'name': fields.char('Action Name', required=True, size=64, translate=True),
+        'name': fields.char('Action Name', required=True, translate=True),
         'condition': fields.char('Condition',
                                  help="Condition verified before executing the server action. If it "
                                  "is not verified, the action will not be executed. The condition is "
@@ -461,16 +488,18 @@ class ir_actions_server(osv.osv):
                                   "- 'Write on a Record': update the values of a record\n"
                                   "- 'Execute several actions': define an action that triggers several other server actions\n"
                                   "- 'Send Email': automatically send an email (available in email_template)"),
-        'usage': fields.char('Action Usage', size=32),
-        'type': fields.char('Action Type', size=32, required=True),
+        'usage': fields.char('Action Usage'),
+        'type': fields.char('Action Type', required=True),
         # Generic
         'sequence': fields.integer('Sequence',
                                    help="When dealing with multiple actions, the execution order is "
                                    "based on the sequence. Low number means high priority."),
         'model_id': fields.many2one('ir.model', 'Base Model', required=True, ondelete='cascade',
                                     help="Base model on which the server action runs."),
+        'model_name': fields.related('model_id', 'model', type='char',
+                                     string='Model Name', readonly=True),
         'menu_ir_values_id': fields.many2one('ir.values', 'More Menu entry', readonly=True,
-                                             help='More menu entry.'),
+                                             help='More menu entry.', copy=False),
         # Client Action
         'action_id': fields.many2one('ir.actions.actions', 'Client Action',
                                      help="Select the client action that has to be executed."),
@@ -526,7 +555,7 @@ class ir_actions_server(osv.osv):
                                         help="Provide an expression that, applied on the current record, gives the field to update."),
         'fields_lines': fields.one2many('ir.server.object.lines', 'server_id',
                                         string='Value Mapping',
-                                        help=""),
+                                        copy=True),
 
         # Fake fields used to implement the placeholder assistant
         'model_object_field': fields.many2one('ir.model.fields', string="Field",
@@ -553,7 +582,7 @@ class ir_actions_server(osv.osv):
         'sequence': 5,
         'code': """# You can use the following variables:
 #  - self: ORM model of the record on which the action is triggered
-#  - object: browse_record of the record on which the action is triggered if there is one, otherwise None
+#  - object: Record on which the action is triggered if there is one, otherwise None
 #  - pool: ORM model pool (i.e. self.pool)
 #  - cr: database cursor
 #  - uid: current user id
@@ -587,16 +616,16 @@ class ir_actions_server(osv.osv):
         # analyze path
         while path:
             step = path.pop(0)
-            column_info = self.pool[current_model_name]._all_columns.get(step)
-            if not column_info:
+            field = self.pool[current_model_name]._fields.get(step)
+            if not field:
                 return (False, None, 'Part of the expression (%s) is not recognized as a column in the model %s.' % (step, current_model_name))
-            column_type = column_info.column._type
-            if column_type not in ['many2one', 'int']:
-                return (False, None, 'Part of the expression (%s) is not a valid column type (is %s, should be a many2one or an int)' % (step, column_type))
-            if column_type == 'int' and path:
+            ftype = field.type
+            if ftype not in ['many2one', 'int']:
+                return (False, None, 'Part of the expression (%s) is not a valid column type (is %s, should be a many2one or an int)' % (step, ftype))
+            if ftype == 'int' and path:
                 return (False, None, 'Part of the expression (%s) is an integer field that is only allowed at the end of an expression' % (step))
-            if column_type == 'many2one':
-                current_model_name = column_info.column._obj
+            if ftype == 'many2one':
+                current_model_name = field.comodel_name
         return (True, current_model_name, None)
 
     def _check_write_expression(self, cr, uid, ids, context=None):
@@ -628,6 +657,10 @@ class ir_actions_server(osv.osv):
             'wkf_field_id': False,
             'crud_model_id': model_id,
         }
+
+        if model_id:
+            values['model_name'] = self.pool.get('ir.model').browse(cr, uid, model_id, context).model
+
         return {'value': values}
 
     def on_change_wkf_wonfig(self, cr, uid, ids, use_relational_model, wkf_field_id, wkf_model_id, model_id, context=None):
@@ -712,19 +745,24 @@ class ir_actions_server(osv.osv):
     def on_change_write_expression(self, cr, uid, ids, write_expression, model_id, context=None):
         """ Check the write_expression and update crud_model_id accordingly """
         values = {}
-        valid, model_name, message = self._check_expression(cr, uid, write_expression, model_id, context=context)
-        if valid:
+        if write_expression:
+            valid, model_name, message = self._check_expression(cr, uid, write_expression, model_id, context=context)
+        else:
+            valid, model_name, message = True, None, False
+            if model_id:
+                model_name = self.pool['ir.model'].browse(cr, uid, model_id, context).model
+        if not valid:
+            return {
+                'warning': {
+                    'title': 'Incorrect expression',
+                    'message': message or 'Invalid expression',
+                }
+            }
+        if model_name:
             ref_model_id = self.pool['ir.model'].search(cr, uid, [('model', '=', model_name)], context=context)[0]
             values['crud_model_id'] = ref_model_id
             return {'value': values}
-        if not message:
-            message = 'Invalid expression'
-        return {
-            'warning': {
-                'title': 'Incorrect expression',
-                'message': message,
-            }
-        }
+        return {'value': {}}
 
     def on_change_crud_model_id(self, cr, uid, ids, crud_model_id, context=None):
         """ When changing the CRUD model, update its stored name also """
@@ -809,7 +847,7 @@ class ir_actions_server(osv.osv):
     def run_action_client_action(self, cr, uid, action, eval_context=None, context=None):
         if not action.action_id:
             raise osv.except_osv(_('Error'), _("Please specify an action to launch!"))
-        return self.pool[action.action_id.type].read(cr, uid, action.action_id.id, context=context)
+        return self.pool[action.action_id.type].read(cr, uid, [action.action_id.id], context=context)[0]
 
     def run_action_code_multi(self, cr, uid, action, eval_context=None, context=None):
         eval(action.code.strip(), eval_context, mode="exec", nocopy=True)  # nocopy allows to return 'action'
@@ -819,33 +857,26 @@ class ir_actions_server(osv.osv):
     def run_action_trigger(self, cr, uid, action, eval_context=None, context=None):
         """ Trigger a workflow signal, depending on the use_relational_model:
 
-         - `base`: base_model_pool.signal_<TRIGGER_NAME>(cr, uid, context.get('active_id'))
+         - `base`: base_model_pool.signal_workflow(cr, uid, context.get('active_id'), <TRIGGER_NAME>)
          - `relational`: find the related model and object, using the relational
-           field, then target_model_pool.signal_<TRIGGER_NAME>(cr, uid, target_id)
+           field, then target_model_pool.signal_workflow(cr, uid, target_id, <TRIGGER_NAME>)
         """
-        obj_pool = self.pool[action.model_id.model]
-        if action.use_relational_model == 'base':
-            target_id = context.get('active_id')
-            target_pool = obj_pool
-        else:
-            value = getattr(obj_pool.browse(cr, uid, context.get('active_id'), context=context), action.wkf_field_id.name)
-            if action.wkf_field_id.ttype == 'many2one':
-                target_id = value.id
-            else:
-                target_id = value
-            target_pool = self.pool[action.wkf_model_id.model]
+        # weird signature and calling -> no self.env, use action param's
+        record = action.env[action.model_id.model].browse(context['active_id'])
+        if action.use_relational_model == 'relational':
+            record = getattr(record, action.wkf_field_id.name)
+            if not isinstance(record, openerp.models.BaseModel):
+                record = action.env[action.wkf_model_id.model].browse(record)
 
-        trigger_name = action.wkf_transition_id.signal
-
-        workflow.trg_validate(uid, target_pool._name, target_id, trigger_name, cr)
+        record.signal_workflow(action.wkf_transition_id.signal)
 
     def run_action_multi(self, cr, uid, action, eval_context=None, context=None):
-        res = []
+        res = False
         for act in action.child_ids:
-            result = self.run(cr, uid, [act.id], context)
+            result = self.run(cr, uid, [act.id], context=context)
             if result:
-                res.append(result)
-        return res and res[0] or False
+                res = result
+        return res
 
     def run_action_object_write(self, cr, uid, action, eval_context=None, context=None):
         """ Write server action.
@@ -859,11 +890,7 @@ class ir_actions_server(osv.osv):
         """
         res = {}
         for exp in action.fields_lines:
-            if exp.type == 'equation':
-                expr = eval(exp.value, eval_context)
-            else:
-                expr = exp.value
-            res[exp.col1.name] = expr
+            res[exp.col1.name] = exp.eval_value(eval_context=eval_context)[exp.id]
 
         if action.use_write == 'current':
             model = action.model_id.model
@@ -896,11 +923,7 @@ class ir_actions_server(osv.osv):
         """
         res = {}
         for exp in action.fields_lines:
-            if exp.type == 'equation':
-                expr = eval(exp.value, eval_context)
-            else:
-                expr = exp.value
-            res[exp.col1.name] = expr
+            res[exp.col1.name] = exp.eval_value(eval_context=eval_context)[exp.id]
 
         if action.use_create in ['new', 'copy_current']:
             model = action.model_id.model
@@ -944,7 +967,8 @@ class ir_actions_server(osv.osv):
             'uid': uid,
             'user': user,
             'context': context,
-            'workflow': workflow
+            'workflow': workflow,
+            'Warning': openerp.exceptions.Warning,
         }
 
     def run(self, cr, uid, ids, context=None):
@@ -1002,7 +1026,9 @@ class ir_actions_server(osv.osv):
 
 class ir_server_object_lines(osv.osv):
     _name = 'ir.server.object.lines'
+    _description = 'Server Action value mapping'
     _sequence = 'ir_actions_id_seq'
+
     _columns = {
         'server_id': fields.many2one('ir.actions.server', 'Related Server Action'),
         'col1': fields.many2one('ir.model.fields', 'Field', required=True),
@@ -1015,10 +1041,25 @@ class ir_server_object_lines(osv.osv):
             ('equation', 'Python expression')
         ], 'Evaluation Type', required=True, change_default=True),
     }
+
     _defaults = {
         'type': 'value',
     }
 
+    def eval_value(self, cr, uid, ids, eval_context=None, context=None):
+        res = dict.fromkeys(ids, False)
+        for line in self.browse(cr, uid, ids, context=context):
+            expr = line.value
+            if line.type == 'equation':
+                expr = eval(line.value, eval_context)
+            elif line.col1.ttype in ['many2one', 'integer']:
+                try:
+                    expr = int(line.value)
+                except Exception:
+                    pass
+            res[line.id] = expr
+        return res
+
 
 TODO_STATES = [('open', 'To Do'),
                ('done', 'Done')]
@@ -1035,7 +1076,7 @@ class ir_actions_todo(osv.osv):
             'ir.actions.actions', 'Action', select=True, required=True),
         'sequence': fields.integer('Sequence'),
         'state': fields.selection(TODO_STATES, string='Status', required=True),
-        'name': fields.char('Name', size=64),
+        'name': fields.char('Name'),
         'type': fields.selection(TODO_TYPES, 'Type', required=True,
             help="""Manual: Launched manually.
 Automatic: Runs whenever the system is reconfigured.
@@ -1051,7 +1092,16 @@ Launch Manually Once: after having been launched manually, it sets automatically
     _order="sequence,id"
 
     def name_get(self, cr, uid, ids, context=None):
-        return [(action["id"], "%s" % (action['action_id'][1])) for action in self.read(cr, uid, ids, ['action_id'], context=context)]
+        return [(rec.id, rec.action_id.name) for rec in self.browse(cr, uid, ids, context=context)]
+
+    def name_search(self, cr, user, name, args=None, operator='ilike', context=None, limit=100):
+        if args is None:
+            args = []
+        if name:
+            ids = self.search(cr, user, [('action_id', operator, name)] + args, limit=limit)
+            return self.name_get(cr, user, ids, context=context)
+        return super(ir_actions_todo, self).name_search(cr, user, name, args=args, operator=operator, context=context, limit=limit)
+
 
     def action_launch(self, cr, uid, ids, context=None):
         """ Launch Action of Wizard"""
@@ -1061,10 +1111,10 @@ Launch Manually Once: after having been launched manually, it sets automatically
             wizard.write({'state': 'done'})
 
         # Load action
-        act_type = self.pool.get('ir.actions.actions').read(cr, uid, wizard.action_id.id, ['type'], context=context)
+        act_type = wizard.action_id.type
 
-        res = self.pool[act_type['type']].read(cr, uid, wizard.action_id.id, [], context=context)
-        if act_type['type'] != 'ir.actions.act_window':
+        res = self.pool[act_type].read(cr, uid, [wizard.action_id.id], [], context=context)[0]
+        if act_type != 'ir.actions.act_window':
             return res
         res.setdefault('context','{}')
         res['nodestroy'] = True
@@ -1133,6 +1183,8 @@ class ir_actions_act_client(osv.osv):
 
     def _get_params(self, cr, uid, ids, field_name, arg, context):
         result = {}
+        # Need to remove bin_size from context, to obtains the binary and not the length.
+        context = dict(context, bin_size_params_store=False)
         for record in self.browse(cr, uid, ids, context=context):
             result[record.id] = record.params_store and eval(record.params_store, {'uid': uid}) or False
         return result
@@ -1144,14 +1196,14 @@ class ir_actions_act_client(osv.osv):
             self.write(cr, uid, id, {'params_store': field_value}, context=context)
 
     _columns = {
-        'name': fields.char('Action Name', required=True, size=64, translate=True),
-        'tag': fields.char('Client action tag', size=64, required=True,
+        'name': fields.char('Action Name', required=True, translate=True),
+        'tag': fields.char('Client action tag', required=True,
                            help="An arbitrary string, interpreted by the client"
                                 " according to its own needs and wishes. There "
                                 "is no central tag repository across clients."),
-        'res_model': fields.char('Destination Model', size=64, 
+        'res_model': fields.char('Destination Model', 
             help="Optional model, mostly used for needactions."),
-        'context': fields.char('Context Value', size=250, required=True,
+        'context': fields.char('Context Value', required=True,
             help="Context dictionary as Python expression, empty by default (Default: {})"),
         'params': fields.function(_get_params, fnct_inv=_set_params,
                                   type='binary', 
@@ -1166,7 +1218,4 @@ class ir_actions_act_client(osv.osv):
 
     }
 
-
-
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-