1 # -*- encoding: utf-8 -*-
2 ##############################################################################
4 # Copyright (c) 2004-2008 TINY SPRL. (http://tiny.be) All Rights Reserved.
8 # WARNING: This program as such is intended to be used by professional
9 # programmers who take the whole responsability of assessing all potential
10 # consequences resulting from its eventual inadequacies and bugs
11 # End users who are looking for a ready-to-use solution with commercial
12 # garantees and support are strongly adviced to contract a Free Software
15 # This program is Free Software; you can redistribute it and/or
16 # modify it under the terms of the GNU General Public License
17 # as published by the Free Software Foundation; either version 2
18 # of the License, or (at your option) any later version.
20 # This program is distributed in the hope that it will be useful,
21 # but WITHOUT ANY WARRANTY; without even the implied warranty of
22 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 # GNU General Public License for more details.
25 # You should have received a copy of the GNU General Public License
26 # along with this program; if not, write to the Free Software
27 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 ##############################################################################
35 from rpc
import RPCProxy
43 from field
import O2MField
45 class EvalEnvironment(object):
46 def __init__(self
, parent
):
49 def __getattr__(self
, item
):
50 if item
=='parent' and self
.parent
.parent
:
51 return EvalEnvironment(self
.parent
.parent
)
52 if item
=="current_date":
53 return time
.strftime('%Y-%m-%d')
56 return self
.parent
.get(includeid
=True)[item
]
59 class ModelRecord(signal_event
.signal_event
):
60 def __init__(self
, resource
, id, group
=None, parent
=None, new
=False ):
61 super(ModelRecord
, self
).__init
__()
62 self
.resource
= resource
63 self
.rpc
= RPCProxy(self
.resource
)
71 self
.modified_fields
= {}
72 self
.read_time
= time
.time()
73 for key
,val
in self
.mgroup
.mfields
.items():
74 self
.value
[key
] = val
.create(self
)
75 if (new
and val
.attrs
['type']=='one2many') and (val
.attrs
.get('mode','tree,form').startswith('form')):
76 mod
= self
.value
[key
].model_new()
77 self
.value
[key
].model_add(mod
)
79 def __getitem__(self
, name
):
80 return self
.mgroup
.mfields
.get(name
, False)
83 return '<ModelRecord %s@%s>' % (self
.id, self
.resource
)
85 def is_modified(self
):
89 return self
.mgroup
.mfields
91 def _check_load(self
):
97 def get(self
, get_readonly
=True, includeid
=False, check_load
=True, get_modifiedonly
=False):
101 for name
, field
in self
.mgroup
.mfields
.items():
102 if (get_readonly
or not field
.get_state_attrs(self
).get('readonly', False)) \
103 and (not get_modifiedonly
or (field
.name
in self
.modified_fields
or isinstance(field
, O2MField
))):
104 value
.append((name
, field
.get(self
, readonly
=get_readonly
,
105 modified
=get_modifiedonly
)))
108 value
['id'] = self
.id
115 def save(self
, reload=True):
118 value
= self
.get(get_readonly
=False)
119 self
.id = self
.rpc
.create(value
, self
.context_get())
121 if not self
.is_modified():
123 value
= self
.get(get_readonly
=False, get_modifiedonly
=True)
124 context
= self
.context_get()
125 context
= context
.copy()
126 context
['read_delta']= time
.time()-self
.read_time
127 if not rpc
.session
.rpc_exec_auth('/object', 'execute', self
.resource
, 'write', [self
.id], value
, context
):
134 def default_get(self
, domain
=[], context
={}):
135 if len(self
.mgroup
.fields
):
136 val
= self
.rpc
.default_get(self
.mgroup
.fields
.keys(), context
)
138 if d
[0] in self
.mgroup
.fields
:
141 if d
[1] == 'in' and len(d
[2]) == 1:
143 self
.set_default(val
)
146 name
= self
.rpc
.name_get([self
.id], rpc
.session
.context
)[0]
149 def validate_set(self
):
150 change
= self
._check
_load
()
151 for fname
in self
.mgroup
.mfields
:
152 field
= self
.mgroup
.mfields
[fname
]
153 change
= change
or not field
.get_state_attrs(self
).get('valid', True)
154 field
.get_state_attrs(self
)['valid'] = True
156 self
.signal('record-changed')
162 for fname
in self
.mgroup
.mfields
:
163 if not self
.mgroup
.mfields
[fname
].validate(self
):
167 def _get_invalid_fields(self
):
169 for fname
, field
in self
.mgroup
.mfields
.items():
170 if not field
.get_state_attrs(self
).get('valid', True):
171 res
.append((fname
, field
.attrs
['string']))
173 invalid_fields
= property(_get_invalid_fields
)
175 def context_get(self
):
176 return self
.mgroup
.context
178 def get_default(self
):
180 value
= dict([(name
, field
.get_default(self
))
181 for name
, field
in self
.mgroup
.mfields
.items()])
184 def set_default(self
, val
):
185 for fieldname
, value
in val
.items():
186 if fieldname
not in self
.mgroup
.mfields
:
188 self
.mgroup
.mfields
[fieldname
].set_default(self
, value
)
190 self
.signal('record-changed')
192 def set(self
, val
, modified
=False, signal
=True):
194 for fieldname
, value
in val
.items():
195 if fieldname
not in self
.mgroup
.mfields
:
197 if isinstance(self
.mgroup
.mfields
[fieldname
], field
.O2MField
):
198 later
[fieldname
]=value
200 self
.mgroup
.mfields
[fieldname
].set(self
, value
, modified
=modified
)
201 for fieldname
, value
in later
.items():
202 self
.mgroup
.mfields
[fieldname
].set(self
, value
, modified
=modified
)
204 self
.modified
= modified
205 if not self
.modified
:
206 self
.modified_fields
= {}
208 self
.signal('record-changed')
213 c
= rpc
.session
.context
.copy()
214 c
.update(self
.context_get())
215 res
= self
.rpc
.read([self
.id], self
.mgroup
.mfields
.keys(), c
)
218 self
.read_time
= time
.time()
221 def expr_eval(self
, dom
, check_load
=True):
222 if not isinstance(dom
, basestring
):
227 for name
, mfield
in self
.mgroup
.mfields
.items():
228 d
[name
] = mfield
.get(self
, check_load
=check_load
)
230 d
['current_date'] = time
.strftime('%Y-%m-%d')
232 d
['context'] = self
.context_get()
233 d
['active_id'] = self
.id
235 d
['parent'] = EvalEnvironment(self
.parent
)
236 val
= tools
.expr_eval(dom
, d
)
239 #XXX Shoud use changes of attributes (ro, ...)
240 def on_change(self
, callback
):
241 match
= re
.match('^(.*?)\((.*)\)$', callback
)
243 raise Exception, 'ERROR: Wrong on_change trigger: %s' % callback
244 func_name
= match
.group(1)
245 arg_names
= [n
.strip() for n
in match
.group(2).split(',')]
246 args
= [self
.expr_eval(arg
) for arg
in arg_names
]
247 ids
= self
.id and [self
.id] or []
248 response
= getattr(self
.rpc
, func_name
)(ids
, *args
)
250 self
.set(response
.get('value', {}), modified
=True)
251 if 'domain' in response
:
252 for fieldname
, value
in response
['domain'].items():
253 if fieldname
not in self
.mgroup
.mfields
:
255 self
.mgroup
.mfields
[fieldname
].attrs
['domain'] = value
256 self
.signal('record-changed')
258 def on_change_attrs(self
, callback
):
259 self
.signal('attrs-changed')
261 def cond_default(self
, field
, value
):
262 ir
= RPCProxy('ir.values')
263 values
= ir
.get('default', '%s=%s' % (field
, value
),
264 [(self
.resource
, False)], False, {})
266 for index
, fname
, value
in values
:
268 self
.set_default(data
)
270 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: