1
##############################################################################
3
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
7
# WARNING: This program as such is intended to be used by professional
8
# programmers who take the whole responsability of assessing all potential
9
# consequences resulting from its eventual inadequacies and bugs
10
# End users who are looking for a ready-to-use solution with commercial
11
# garantees and support are strongly adviced to contract a Free Software
14
# This program is Free Software; you can redistribute it and/or
15
# modify it under the terms of the GNU General Public License
16
# as published by the Free Software Foundation; either version 2
17
# of the License, or (at your option) any later version.
19
# This program is distributed in the hope that it will be useful,
20
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
# GNU General Public License for more details.
24
# You should have received a copy of the GNU General Public License
25
# along with this program; if not, write to the Free Software
26
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28
##############################################################################
35
from rpc import RPCProxy
36
from editabletree import EditableTreeView
37
from widget.view import interface
41
from widget.view.form_gtk.many2one import dialog as M2ODialog
42
from modules.gui.window.win_search import win_search
45
def send_keys(renderer, editable, position, treeview):
46
editable.connect('key_press_event', treeview.on_keypressed)
47
editable.connect('editing_done', treeview.on_editing_done)
49
def sort_model(column, treeview):
50
model = treeview.get_model()
51
model.sort(column.name)
53
class parser_tree(interface.parser_interface):
54
def parse(self, model, root_node, fields):
55
attrs = tools.node_attributes(root_node)
56
on_write = attrs.get('on_write', '')
57
editable = attrs.get('editable', False)
59
treeview = EditableTreeView(editable)
61
treeview = gtk.TreeView()
62
treeview.editable = editable
63
treeview.colors = dict()
64
self.treeview = treeview
65
for color_spec in attrs.get('colors', '').split(';'):
67
colour, test = color_spec.split(':')
68
treeview.colors[colour] = test
69
treeview.set_property('rules-hint', True)
71
self.title = attrs.get('string', 'Unknown')
73
for node in root_node.childNodes:
74
node_attrs = tools.node_attributes(node)
75
if node.localName == 'field':
76
fname = node_attrs['name']
77
for boolean_fields in ('readonly', 'required'):
78
if boolean_fields in node_attrs:
79
node_attrs[boolean_fields] = bool(int(node_attrs[boolean_fields]))
80
fields[fname].update(node_attrs)
81
node_attrs.update(fields[fname])
82
cell = Cell(fields[fname]['type'])(fname, treeview, node_attrs)
83
renderer = cell.renderer
85
renderer.set_property('editable', True)
86
renderer.connect_after('editing-started', send_keys, treeview)
87
# renderer.connect_after('editing-canceled', self.editing_canceled)
89
col = gtk.TreeViewColumn(fields[fname]['string'], renderer)
91
col._type = fields[fname]['type']
92
col.set_cell_data_func(renderer, cell.setter)
93
col.set_clickable(True)
103
if 'width' in fields[fname]:
104
width = int(fields[fname]['width'])
106
width = twidth.get(fields[fname]['type'], 100)
107
col.set_min_width(width)
108
col.connect('clicked', sort_model, treeview)
109
col.set_resizable(True)
110
treeview.append_column(col)
111
return treeview, {}, [], on_write
113
class UnsettableColumn(Exception):
117
def __new__(self, type):
118
klass = CELLTYPES.get(type, CELLTYPES['char'])
123
def __init__(self, field_name, treeview=None, attrs={}):
124
self.field_name = field_name
126
self.renderer = gtk.CellRendererText()
127
self.treeview = treeview
129
def setter(self, column, cell, store, iter):
130
model = store.get_value(iter, 0)
131
text = self.get_textual_value(model)
132
cell.set_property('text', text)
133
color = self.get_color(model)
134
cell.set_property('foreground', str(color))
135
if self.attrs['type'] in ('float', 'int'):
139
cell.set_property('xalign', align)
141
def get_color(self, model):
142
if (model.id is None) and self.treeview.editable:
145
for color, expr in self.treeview.colors.items():
146
if model.expr_eval(expr):
149
return to_display or 'black'
151
def open_remote(self, model, create):
152
raise NotImplementedError
154
def get_textual_value(self, model):
155
return model[self.field_name].get_client() or ''
157
def value_from_text(self, model, text):
162
def value_from_text(self, model, text):
165
class GenericDate(Char):
167
def get_textual_value(self, model):
168
value = model[self.field_name].get_client()
171
date = time.strptime(value, self.server_format)
172
return time.strftime(self.display_format, date)
174
def value_from_text(self, model, text):
178
dt = time.strptime(text, self.display_format)
181
dt = list(time.localtime())
186
return time.strftime(self.server_format, dt)
188
class Date(GenericDate):
189
server_format = '%Y-%m-%d'
190
display_format = '%x'
192
class Datetime(GenericDate):
193
server_format = '%Y-%m-%d %H:%M:%S'
194
display_format = '%x %H:%M:%S'
197
def get_textual_value(self, model):
198
_, digit = self.attrs.get('digits', (16,2) )
199
return locale.format('%.'+str(digit)+'f', model[self.field_name].get_client() or 0.0)
201
def value_from_text(self, model, text):
202
return locale.atof(text)
206
def value_from_text(self, model, text):
210
relation = model[self.field_name].attrs['relation']
211
rpc = RPCProxy(relation)
213
domain = model[self.field_name].domain_get()
214
context = model[self.field_name].context_get()
216
names = rpc.name_search(text, domain, 'ilike', context)
218
return self.search_remote(relation, [x[0] for x in names],
219
domain=domain, context=context)
222
def open_remote(self, model, create=True, changed=False, text=None):
223
modelfield = model[self.field_name]
224
relation = modelfield.attrs['relation']
228
elif modelfield.internal and not modelfield.modified and not changed:
229
id = modelfield.internal[0]
231
rpc = RPCProxy(relation)
233
domain=modelfield.domain_get()
234
context=modelfield.context_get()
236
names = rpc.name_search(text, domain, 'ilike', context)
238
return True, names[0]
239
searched = self.search_remote(relation, [x[0] for x in names], domain=domain, context=context)
241
return True, searched
243
dia = M2ODialog(relation, id)
244
new_value = dia.run()
247
return True, new_value[1]
251
def search_remote(self, relation, ids=[], domain=[], context={}):
252
rpc = RPCProxy(relation)
254
win = win_search(relation, sel_multi=False, ids=ids)
257
return rpc.name_get([found[0]], context)[0]
263
def get_textual_value(self, model):
264
return '( '+str(len(model[self.field_name].internal.models or [])) + ' )'
266
def value_from_text(self, model, text):
267
raise UnsettableColumn('Can not set column of type o2m')
271
def get_textual_value(self, model):
272
value = model[self.field_name].internal
274
return '(%s)' % len(value)
278
def value_from_text(self, model, text):
279
raise UnsettableColumn('Can not set column of type m2m')
282
class Selection(Char):
284
def __init__(self, *args):
285
super(Selection, self).__init__(*args)
286
self.renderer = gtk.CellRendererCombo()
287
selection_data = gtk.ListStore(str, str)
288
for x in self.attrs.get('selection', []):
289
selection_data.append(x)
290
self.renderer.set_property('model', selection_data)
291
self.renderer.set_property('text-column', 1)
293
def get_textual_value(self, model):
294
selection = dict(model[self.field_name].attrs['selection'])
295
return selection.get(model[self.field_name].internal, '')
297
def value_from_text(self, model, text):
298
selection = model[self.field_name].attrs['selection']
299
for val, txt in selection:
304
CELLTYPES = dict(char=Char,