Add ModelView.button_change

issue4397
review7781002
This commit is contained in:
Cédric Krier
2015-03-16 12:56:11 +01:00
parent af292cac78
commit ad5eb3ed97
4 changed files with 54 additions and 10 deletions
+1
View File
@@ -1,3 +1,4 @@
* Add button_change
* Add support for PyPy
* Add support for psycopg2cffi
* Add noeval on PYSONDecoder
+9
View File
@@ -129,6 +129,15 @@ Static methods:
Same as :meth:`ModelView.button` but return the action id of the XML `id`
action.
.. staticmethod:: ModelView.button_change([\*fields])
Same as :meth:`ModelView.button` but for button that change values of the
fields on client side (similar to :ref:`on_change
<ref-models-fields-on_change>`).
.. warning::
Only on instance methods.
Class methods:
.. classmethod:: ModelView.fields_view_get([view_id[, view_type[, toolbar]]])
+44 -4
View File
@@ -125,10 +125,12 @@ class ModelView(Model):
else:
cls.__depend_methods = collections.defaultdict(set)
for field_name in dir(cls):
field = getattr(cls, field_name)
if not isinstance(field, fields.Field):
continue
if hasattr(cls, '__change_buttons'):
cls.__change_buttons = cls.__change_buttons.copy()
else:
cls.__change_buttons = collections.defaultdict(set)
def setup_field(field, field_name):
for attribute in ('on_change', 'on_change_with', 'autocomplete',
'selection_change_with'):
if attribute == 'selection_change_with':
@@ -159,6 +161,17 @@ class ModelView(Model):
# Decorate on_change to always return self
setattr(cls, function_name, on_change(function))
def setup_callable(function, name):
if hasattr(function, 'change'):
cls.__change_buttons[name] |= function.change
for name in dir(cls):
attr = getattr(cls, name)
if isinstance(attr, fields.Field):
setup_field(attr, name)
elif isinstance(attr, collections.Callable):
setup_callable(attr, name)
@classmethod
def __post_setup__(cls):
super(ModelView, cls).__post_setup__()
@@ -181,6 +194,15 @@ class ModelView(Model):
cls.__rpc__.setdefault(function_name,
RPC(instantiate=0, result=result))
for button in cls._buttons:
method = getattr(cls, button)
if not hasattr(method, 'im_self') or method.im_self:
cls.__rpc__.setdefault(button,
RPC(readonly=False, instantiate=0))
else:
cls.__rpc__.setdefault(button,
RPC(instantiate=0, result=on_change_result))
# Update depend on methods
for (field_name, attribute), others in (
cls.__depend_methods.iteritems()):
@@ -540,6 +562,15 @@ class ModelView(Model):
states['readonly'] = True
element.set('states', encoder.encode(states))
change = cls.__change_buttons[button_name]
if change:
element.set('change', encoder.encode(list(change)))
method = getattr(cls, button_name)
if not hasattr(method, 'im_self') or method.im_self:
element.set('type', 'class')
else:
element.set('type', 'instance')
# translate view
if Transaction().language != 'en_US':
for attr in ('string', 'sum', 'confirm', 'help'):
@@ -611,6 +642,15 @@ class ModelView(Model):
return wrapper
return decorator
@staticmethod
def button_change(*fields):
def decorator(func):
func = ModelView.button(func)
func = on_change(func)
func.change = set(fields)
return func
return decorator
def on_change(self, fieldnames):
for fieldname in sorted(fieldnames):
method = getattr(self, 'on_change_%s' % fieldname, None)
-6
View File
@@ -16,7 +16,6 @@ from trytond.transaction import Transaction
from trytond.cache import Cache
from trytond.exceptions import UserError, UserWarning, NotLogged, \
ConcurrencyException
from trytond.rpc import RPC
logger = logging.getLogger(__name__)
@@ -105,9 +104,6 @@ def dispatch(host, port, protocol, database_name, user, session, object_type,
for object_name, obj in pool.iterobject(type=type):
for method in obj.__rpc__:
res.append(type + '.' + object_name + '.' + method)
if hasattr(obj, '_buttons'):
for button in obj._buttons:
res.append(type + '.' + object_name + '.' + button)
return res
elif method == 'methodSignature':
return 'signatures not supported'
@@ -139,8 +135,6 @@ def dispatch(host, port, protocol, database_name, user, session, object_type,
if method in obj.__rpc__:
rpc = obj.__rpc__[method]
elif method in getattr(obj, '_buttons', {}):
rpc = RPC(readonly=False, instantiate=0)
else:
raise UserError('Calling method %s on %s %s is not allowed!'
% (method, object_type, object_name))