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
= str(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
.is_wizard
92 return self
.mgroup
.mfields
94 def _check_load(self
):
100 def get(self
, get_readonly
=True, includeid
=False, check_load
=True, get_modifiedonly
=False):
104 for name
, field
in self
.mgroup
.mfields
.items():
105 if (get_readonly
or not field
.get_state_attrs(self
).get('readonly', False)) \
106 and (not get_modifiedonly
or (field
.name
in self
.modified_fields
or isinstance(field
, O2MField
))):
107 value
.append((name
, field
.get(self
, readonly
=get_readonly
,
108 modified
=get_modifiedonly
)))
111 value
['id'] = self
.id
118 def save(self
, reload=True):
121 value
= self
.get(get_readonly
=False)
122 self
.id = self
.rpc
.create(value
, self
.context_get())
124 if not self
.is_modified():
126 value
= self
.get(get_readonly
=False, get_modifiedonly
=True)
127 context
= self
.context_get()
128 context
= context
.copy()
129 context
['read_delta']= time
.time()-self
.read_time
130 if not rpc
.session
.rpc_exec_auth('/object', 'execute', self
.resource
, 'write', [self
.id], value
, context
):
137 def default_get(self
, domain
=[], context
={}):
138 if len(self
.mgroup
.fields
):
139 val
= self
.rpc
.default_get(self
.mgroup
.fields
.keys(), context
)
141 if d
[0] in self
.mgroup
.fields
:
144 if d
[1] == 'in' and len(d
[2]) == 1:
146 self
.set_default(val
)
149 name
= self
.rpc
.name_get([self
.id], rpc
.session
.context
)[0]
152 def validate_set(self
):
153 change
= self
._check
_load
()
154 for fname
in self
.mgroup
.mfields
:
155 field
= self
.mgroup
.mfields
[fname
]
156 change
= change
or not field
.get_state_attrs(self
).get('valid', True)
157 field
.get_state_attrs(self
)['valid'] = True
159 self
.signal('record-changed')
165 for fname
in self
.mgroup
.mfields
:
166 if not self
.mgroup
.mfields
[fname
].validate(self
):
170 def _get_invalid_fields(self
):
172 for fname
, field
in self
.mgroup
.mfields
.items():
173 if not field
.get_state_attrs(self
).get('valid', True):
174 res
.append((fname
, field
.attrs
['string']))
176 invalid_fields
= property(_get_invalid_fields
)
178 def context_get(self
):
179 return self
.mgroup
.context
181 def get_default(self
):
183 value
= dict([(name
, field
.get_default(self
))
184 for name
, field
in self
.mgroup
.mfields
.items()])
187 def set_default(self
, val
):
188 for fieldname
, value
in val
.items():
189 if fieldname
not in self
.mgroup
.mfields
:
191 self
.mgroup
.mfields
[fieldname
].set_default(self
, value
)
193 self
.signal('record-changed')
195 def set(self
, val
, modified
=False, signal
=True):
197 for fieldname
, value
in val
.items():
198 if fieldname
not in self
.mgroup
.mfields
:
200 if isinstance(self
.mgroup
.mfields
[fieldname
], field
.O2MField
):
201 later
[fieldname
]=value
203 self
.mgroup
.mfields
[fieldname
].set(self
, value
, modified
=modified
)
204 for fieldname
, value
in later
.items():
205 self
.mgroup
.mfields
[fieldname
].set(self
, value
, modified
=modified
)
207 self
.modified
= modified
208 if not self
.modified
:
209 self
.modified_fields
= {}
211 self
.signal('record-changed')
216 c
= rpc
.session
.context
.copy()
217 c
.update(self
.context_get())
219 res
= self
.rpc
.read([self
.id], self
.mgroup
.mfields
.keys(), c
)
222 self
.read_time
= time
.time()
225 def expr_eval(self
, dom
, check_load
=True):
226 if not isinstance(dom
, basestring
):
231 for name
, mfield
in self
.mgroup
.mfields
.items():
232 d
[name
] = mfield
.get(self
, check_load
=check_load
)
234 d
['current_date'] = time
.strftime('%Y-%m-%d')
236 d
['context'] = self
.context_get()
237 d
['active_id'] = self
.id
239 d
['parent'] = EvalEnvironment(self
.parent
)
240 val
= tools
.expr_eval(dom
, d
)
243 #XXX Shoud use changes of attributes (ro, ...)
244 def on_change(self
, callback
):
245 match
= re
.match('^(.*?)\((.*)\)$', callback
)
247 raise Exception, 'ERROR: Wrong on_change trigger: %s' % callback
248 func_name
= match
.group(1)
249 arg_names
= [n
.strip() for n
in match
.group(2).split(',')]
250 args
= [self
.expr_eval(arg
) for arg
in arg_names
]
251 ids
= self
.id and [self
.id] or []
252 response
= getattr(self
.rpc
, func_name
)(ids
, *args
)
254 self
.set(response
.get('value', {}), modified
=True)
255 if 'domain' in response
:
256 for fieldname
, value
in response
['domain'].items():
257 if fieldname
not in self
.mgroup
.mfields
:
259 self
.mgroup
.mfields
[fieldname
].attrs
['domain'] = value
260 warning
=response
.get('warning',{})
262 common
.warning(warning
['message'], warning
['title'])
263 self
.signal('record-changed')
265 def on_change_attrs(self
, callback
):
266 self
.signal('attrs-changed')
268 def cond_default(self
, field
, value
):
269 ir
= RPCProxy('ir.values')
270 values
= ir
.get('default', '%s=%s' % (field
, value
),
271 [(self
.resource
, False)], False, {})
273 for index
, fname
, value
in values
:
275 self
.set_default(data
)
277 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: