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 ##############################################################################
31 from rpc
import RPCProxy
34 from sets
import Set
as set
38 class ModelField(object):
40 get: return the values to write to the server
41 get_client: return the value for the client widget (form_gtk)
42 set: save the value from the server
43 set_client: save the value from the widget
46 def __new__(cls
, type):
47 klass
= TYPES
.get(type, CharField
)
51 class CharField(object):
52 def __init__(self
, parent
, attrs
):
55 self
.name
= attrs
['name']
57 self
.default_attrs
= {}
59 def sig_changed(self
, model
):
60 if self
.get_state_attrs(model
).get('readonly', False):
62 if self
.attrs
.get('on_change',False):
63 model
.on_change(self
.attrs
['on_change'])
64 if self
.attrs
.get('change_default', False):
65 model
.cond_default(self
.attrs
['name'], self
.get(model
))
67 def domain_get(self
, model
):
68 dom
= self
.attrs
.get('domain', '[]')
69 return model
.expr_eval(dom
)
71 def context_get(self
, model
, check_load
=True, eval=True):
73 context
.update(self
.parent
.context
)
74 field_context_str
= self
.attrs
.get('context', '{}') or '{}'
76 field_context
= model
.expr_eval('dict(%s)' % field_context_str
, check_load
=check_load
)
77 context
.update(field_context
)
80 def validate(self
, model
):
82 if bool(int(self
.get_state_attrs(model
).get('required', 0))):
83 if not model
.value
[self
.name
]:
85 self
.get_state_attrs(model
)['valid'] = ok
88 def set(self
, model
, value
, test_state
=True, modified
=False):
89 model
.value
[self
.name
] = value
92 model
.modified_fields
.setdefault(self
.name
)
95 def get(self
, model
, check_load
=True, readonly
=True, modified
=False):
96 return model
.value
.get(self
.name
, False) or False
98 def set_client(self
, model
, value
, test_state
=True, force_change
=False):
99 internal
= model
.value
.get(self
.name
, False)
100 self
.set(model
, value
, test_state
)
101 if (internal
or False) != (model
.value
.get(self
.name
,False) or False):
102 model
.modified
= True
103 model
.modified_fields
.setdefault(self
.name
)
104 self
.sig_changed(model
)
105 model
.signal('record-changed', model
)
107 def get_client(self
, model
):
108 return model
.value
[self
.name
] or False
110 def set_default(self
, model
, value
):
111 res
= self
.set(model
, value
)
112 if self
.attrs
.get('on_change',False):
113 model
.on_change(self
.attrs
['on_change'])
116 def get_default(self
, model
):
117 return self
.get(model
)
119 def create(self
, model
):
122 def attrs_set(self
, model
):
123 attrs_changes
= eval(self
.attrs
.get('attrs',"{}"))
124 for k
,v
in attrs_changes
.items():
126 result
= tools
.calc_condition(self
,model
,condition
)
128 self
.get_state_attrs(model
)[k
]=True
129 def state_set(self
, model
, state
='draft'):
130 state_changes
= dict(self
.attrs
.get('states',{}).get(state
,[]))
131 for key
in ('readonly', 'required'):
132 if key
in state_changes
:
133 self
.get_state_attrs(model
)[key
] = state_changes
[key
]
135 self
.get_state_attrs(model
)[key
] = self
.attrs
[key
]
136 if 'value' in state_changes
:
137 self
.set(model
, value
, test_state
=False, modified
=True)
139 def get_state_attrs(self
, model
):
140 if self
.name
not in model
.state_attrs
:
141 model
.state_attrs
[self
.name
] = self
.attrs
.copy()
142 return model
.state_attrs
[self
.name
]
144 class SelectionField(CharField
):
145 def set(self
, model
, value
, test_state
=True, modified
=False):
146 if value
in [sel
[0] for sel
in self
.attrs
['selection']]:
147 super(SelectionField
, self
).set(model
, value
, test_state
, modified
)
149 class FloatField(CharField
):
150 def validate(self
, model
):
151 self
.get_state_attrs(model
)['valid'] = True
154 def set_client(self
, model
, value
, test_state
=True, force_change
=False):
155 internal
= model
.value
[self
.name
]
156 self
.set(model
, value
, test_state
)
157 if abs(float(internal
or 0.0) - float(model
.value
[self
.name
] or 0.0)) >= (10.0**(-int(self
.attrs
.get('digits', (12,4))[1]))):
158 if not self
.get_state_attrs(model
).get('readonly', False):
159 model
.modified
= True
160 model
.modified_fields
.setdefault(self
.name
)
161 self
.sig_changed(model
)
162 model
.signal('record-changed', model
)
164 class IntegerField(CharField
):
166 def get(self
, model
, check_load
=True, readonly
=True, modified
=False):
167 return model
.value
.get(self
.name
, 0) or 0
169 def get_client(self
, model
):
170 return model
.value
[self
.name
] or 0
172 def validate(self
, model
):
173 self
.get_state_attrs(model
)['valid'] = True
177 class M2OField(CharField
):
179 internal = (id, name)
182 def create(self
, model
):
185 def get(self
, model
, check_load
=True, readonly
=True, modified
=False):
186 if model
.value
[self
.name
]:
187 return model
.value
[self
.name
][0] or False
190 def get_client(self
, model
):
192 if model
.value
[self
.name
]:
193 return model
.value
[self
.name
][1]
196 def set(self
, model
, value
, test_state
=False, modified
=False):
197 if value
and isinstance(value
, (int, str, unicode, long)):
198 rpc2
= RPCProxy(self
.attrs
['relation'])
199 result
= rpc2
.name_get([value
], rpc
.session
.context
)
200 model
.value
[self
.name
] = result
[0]
202 model
.value
[self
.name
] = value
204 model
.modified
= True
205 model
.modified_fields
.setdefault(self
.name
)
207 def set_client(self
, model
, value
, test_state
=False, force_change
=False):
208 internal
= model
.value
[self
.name
]
209 self
.set(model
, value
, test_state
)
210 if internal
!= model
.value
[self
.name
]:
211 model
.modified
= True
212 model
.modified_fields
.setdefault(self
.name
)
213 self
.sig_changed(model
)
214 model
.signal('record-changed', model
)
216 self
.sig_changed(model
)
218 class M2MField(CharField
):
223 def __init__(self
, parent
, attrs
):
224 super(M2MField
, self
).__init
__(parent
, attrs
)
226 def create(self
, model
):
229 def get(self
, model
, check_load
=True, readonly
=True, modified
=False):
230 return [(6, 0, model
.value
[self
.name
] or [])]
232 def get_client(self
, model
):
233 return model
.value
[self
.name
] or []
235 def set(self
, model
, value
, test_state
=False, modified
=False):
236 model
.value
[self
.name
] = value
or []
238 model
.modified
= True
239 model
.modified_fields
.setdefault(self
.name
)
241 def set_client(self
, model
, value
, test_state
=False, force_change
=False):
242 internal
= model
.value
[self
.name
]
243 self
.set(model
, value
, test_state
, modified
=False)
244 if set(internal
) != set(value
):
245 model
.modified
= True
246 model
.modified_fields
.setdefault(self
.name
)
247 self
.sig_changed(model
)
248 model
.signal('record-changed', model
)
250 def get_default(self
, model
):
251 return self
.get_client(model
)
253 # Decorator printing debugging output.
255 def debugf(*args
,**kwargs
):
256 print "DEBUG:", f
.__name
__, args
, kwargs
257 retv
= f(*args
,**kwargs
)
258 print "Function returned:", repr(retv
)
263 class debug_function(object):
264 def __init__(self
, f
):
267 def __call__(self
, *args
, **kwargs
):
268 print 'CALL', args
, kwargs
270 return self
.__f
(*args
, **kwargs
)
273 class O2MField(CharField
):
275 internal = ModelRecordGroup of the related objects
278 def __init__(self
, parent
, attrs
):
279 super(O2MField
, self
).__init
__(parent
, attrs
)
282 def create(self
, model
):
283 from widget
.model
.group
import ModelRecordGroup
284 mod
= ModelRecordGroup(resource
=self
.attrs
['relation'], fields
={}, parent
=model
)
285 mod
.signal_connect(mod
, 'model-changed', self
._model
_changed
)
288 def _model_changed(self
, group
, model
):
289 model
.parent
.modified
= True
290 model
.parent
.modified_fields
.setdefault(self
.name
)
291 self
.sig_changed(model
.parent
)
292 self
.parent
.signal('record-changed', model
)
294 def get_client(self
, model
):
295 return model
.value
[self
.name
]
297 def get(self
, model
, check_load
=True, readonly
=True, modified
=False):
298 if not model
.value
[self
.name
]:
301 for model2
in model
.value
[self
.name
].models
:
302 if (modified
and not model2
.is_modified()) or \
303 (not model2
.id and not model2
.is_modified()):
306 result
.append((1,model2
.id, model2
.get(check_load
=check_load
, get_readonly
=readonly
)))
308 result
.append((0,0, model2
.get(check_load
=check_load
, get_readonly
=readonly
)))
309 for id in model
.value
[self
.name
].model_removed
:
310 result
.append((2,id, False))
313 def set(self
, model
, value
, test_state
=False, modified
=False):
314 from widget
.model
.group
import ModelRecordGroup
315 mod
= ModelRecordGroup(resource
=self
.attrs
['relation'], fields
={}, parent
=model
)
316 mod
.signal_connect(mod
, 'model-changed', self
._model
_changed
)
317 model
.value
[self
.name
] =mod
318 #self.internal.signal_connect(self.internal, 'model-changed', self._model_changed)
319 model
.value
[self
.name
].pre_load(value
, display
=False)
320 #self.internal.signal_connect(self.internal, 'model-changed', self._model_changed)
322 def set_client(self
, model
, value
, test_state
=False, force_change
=False):
323 self
.set(model
, value
, test_state
=test_state
)
324 model
.signal('record-changed', model
)
326 def set_default(self
, model
, value
):
327 from widget
.model
.group
import ModelRecordGroup
329 if value
and len(value
):
330 context
= self
.context_get(model
)
331 rpc2
= RPCProxy(self
.attrs
['relation'])
332 fields
= rpc2
.fields_get(value
[0].keys(), context
)
334 model
.value
[self
.name
] = ModelRecordGroup(resource
=self
.attrs
['relation'], fields
=fields
, parent
=model
)
335 model
.value
[self
.name
].signal_connect(model
.value
[self
.name
], 'model-changed', self
._model
_changed
)
337 for record
in (value
or []):
338 mod
= model
.value
[self
.name
].model_new(default
=False)
339 mod
.set_default(record
)
340 model
.value
[self
.name
].model_add(mod
)
341 model
.value
[self
.name
].current_model
= mod
342 #mod.signal('record-changed')
345 def get_default(self
, model
):
346 res
= map(lambda x
: x
.get_default(), model
.value
[self
.name
].models
or [])
349 def validate(self
, model
):
351 for model2
in model
.value
[self
.name
].models
:
352 if not model2
.validate():
353 if not model2
.is_modified():
354 model
.value
[self
.name
].models
.remove(model2
)
357 if not super(O2MField
, self
).validate(model
):
359 self
.get_state_attrs(model
)['valid'] = ok
362 class ReferenceField(CharField
):
363 def get_client(self
, model
):
364 if model
.value
[self
.name
]:
365 return model
.value
[self
.name
]
368 def get(self
, model
, check_load
=True, readonly
=True, modified
=False):
369 if model
.value
[self
.name
]:
370 return '%s,%d' % (model
.value
[self
.name
][0], model
.value
[self
.name
][1][0])
373 def set_client(self
, model
, value
, test_state
=False, force_change
=False):
374 internal
= model
.value
[self
.name
]
375 model
.value
[self
.name
] = value
376 if (internal
or False) != (model
.value
[self
.name
] or False):
377 model
.modified
= True
378 model
.modified_fields
.setdefault(self
.name
)
379 self
.sig_changed(model
)
380 model
.signal('record-changed', model
)
382 def set(self
, model
, value
, test_state
=False, modified
=False):
384 model
.value
[self
.name
] = False
386 ref_model
, id = value
.split(',')
387 rpc2
= RPCProxy(ref_model
)
388 result
= rpc2
.name_get([id], rpc
.session
.context
)
390 model
.value
[self
.name
] = ref_model
, result
[0]
392 model
.value
[self
.name
] = False
394 model
.modified
= True
395 model
.modified_fields
.setdefault(self
.name
)
399 'float_time': FloatField
,
400 'integer' : IntegerField
,
401 'float' : FloatField
,
402 'many2one' : M2OField
,
403 'many2many' : M2MField
,
404 'one2many' : O2MField
,
405 'reference' : ReferenceField
,
406 'selection': SelectionField
,
407 'boolean': IntegerField
,
411 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: