~openerp-dev/openobject-client/6.0-opw-595350-rgo

« back to all changes in this revision

Viewing changes to bin/widget/view/tree_gtk/parser.py

  • Committer: pinky
  • Date: 2006-12-07 13:41:40 UTC
  • Revision ID: pinky-56e9b555eeb500d42202250a3456cfa2a6dc78c7
New trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
##############################################################################
 
2
#
 
3
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
 
4
#
 
5
# $Id$
 
6
#
 
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
 
12
# Service Company
 
13
#
 
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.
 
18
#
 
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.
 
23
#
 
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.
 
27
#
 
28
##############################################################################
 
29
 
 
30
import locale
 
31
import gtk
 
32
from gtk import glade
 
33
 
 
34
import tools
 
35
from rpc import RPCProxy
 
36
from editabletree import EditableTreeView
 
37
from widget.view import interface
 
38
 
 
39
import time
 
40
 
 
41
from widget.view.form_gtk.many2one import dialog as M2ODialog
 
42
from modules.gui.window.win_search import win_search
 
43
 
 
44
 
 
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)
 
48
 
 
49
def sort_model(column, treeview):
 
50
        model = treeview.get_model()
 
51
        model.sort(column.name)
 
52
 
 
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)
 
58
                if editable:
 
59
                        treeview = EditableTreeView(editable)
 
60
                else:
 
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(';'):
 
66
                        if color_spec:
 
67
                                colour, test = color_spec.split(':')
 
68
                                treeview.colors[colour] = test
 
69
                treeview.set_property('rules-hint', True)
 
70
                if not self.title:
 
71
                        self.title = attrs.get('string', 'Unknown')
 
72
 
 
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
 
84
                                if editable:
 
85
                                        renderer.set_property('editable', True)
 
86
                                        renderer.connect_after('editing-started', send_keys, treeview)
 
87
#                                       renderer.connect_after('editing-canceled', self.editing_canceled)
 
88
 
 
89
                                col = gtk.TreeViewColumn(fields[fname]['string'], renderer)
 
90
                                col.name = fname
 
91
                                col._type = fields[fname]['type']
 
92
                                col.set_cell_data_func(renderer, cell.setter)
 
93
                                col.set_clickable(True)
 
94
                                twidth = {
 
95
                                        'integer': 60,
 
96
                                        'float': 80,
 
97
                                        'date': 70,
 
98
                                        'datetime': 120,
 
99
                                        'selection': 90,
 
100
                                        'char': 100,
 
101
                                        'one2many': 50,
 
102
                                }
 
103
                                if 'width' in fields[fname]:
 
104
                                        width = int(fields[fname]['width'])
 
105
                                else:
 
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
 
112
 
 
113
class UnsettableColumn(Exception):
 
114
        pass
 
115
 
 
116
class Cell(object):
 
117
        def __new__(self, type):
 
118
                klass = CELLTYPES.get(type, CELLTYPES['char'])
 
119
                return klass
 
120
 
 
121
 
 
122
class Char(object):
 
123
        def __init__(self, field_name, treeview=None, attrs={}):
 
124
                self.field_name = field_name
 
125
                self.attrs = attrs
 
126
                self.renderer = gtk.CellRendererText()
 
127
                self.treeview = treeview
 
128
 
 
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'):
 
136
                        align = 1
 
137
                else:
 
138
                        align = 0
 
139
                cell.set_property('xalign', align)
 
140
 
 
141
        def get_color(self, model):
 
142
                if (model.id is None) and self.treeview.editable:
 
143
                        return 'red'
 
144
                to_display = ''
 
145
                for color, expr in self.treeview.colors.items():
 
146
                        if model.expr_eval(expr):
 
147
                                to_display = color
 
148
                                break
 
149
                return to_display or 'black'
 
150
 
 
151
        def open_remote(self, model, create):
 
152
                raise NotImplementedError
 
153
 
 
154
        def get_textual_value(self, model):
 
155
                return model[self.field_name].get_client() or ''
 
156
 
 
157
        def value_from_text(self, model, text):
 
158
                return text
 
159
 
 
160
class Int(Char):
 
161
 
 
162
        def value_from_text(self, model, text):
 
163
                return int(text)
 
164
 
 
165
class GenericDate(Char):
 
166
 
 
167
        def get_textual_value(self, model):
 
168
                value = model[self.field_name].get_client()
 
169
                if not value:
 
170
                        return ''
 
171
                date = time.strptime(value, self.server_format)
 
172
                return time.strftime(self.display_format, date)
 
173
 
 
174
        def value_from_text(self, model, text):
 
175
                if not text:
 
176
                        return False
 
177
                try:
 
178
                        dt = time.strptime(text, self.display_format)
 
179
                except:
 
180
                        try:
 
181
                                dt = list(time.localtime())
 
182
                                dt[2] = int(text)
 
183
                                dt = tuple(dt)
 
184
                        except:
 
185
                                return False
 
186
                return time.strftime(self.server_format, dt)
 
187
 
 
188
class Date(GenericDate):
 
189
        server_format = '%Y-%m-%d'
 
190
        display_format = '%x'
 
191
 
 
192
class Datetime(GenericDate):
 
193
        server_format = '%Y-%m-%d %H:%M:%S'
 
194
        display_format = '%x %H:%M:%S'
 
195
 
 
196
class Float(Char):
 
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)
 
200
 
 
201
        def value_from_text(self, model, text):
 
202
                return locale.atof(text)
 
203
 
 
204
class M2O(Char):
 
205
 
 
206
        def value_from_text(self, model, text):
 
207
                if not text:
 
208
                        return False
 
209
 
 
210
                relation = model[self.field_name].attrs['relation']
 
211
                rpc = RPCProxy(relation)
 
212
 
 
213
                domain = model[self.field_name].domain_get()
 
214
                context = model[self.field_name].context_get()
 
215
 
 
216
                names = rpc.name_search(text, domain, 'ilike', context)
 
217
                if len(names) != 1:
 
218
                        return self.search_remote(relation, [x[0] for x in names],
 
219
                                                         domain=domain, context=context)
 
220
                return names[0]
 
221
 
 
222
        def open_remote(self, model, create=True, changed=False, text=None):
 
223
                modelfield = model[self.field_name]
 
224
                relation = modelfield.attrs['relation']
 
225
                
 
226
                if create:
 
227
                        id = None
 
228
                elif modelfield.internal and not modelfield.modified and not changed:
 
229
                        id = modelfield.internal[0]
 
230
                else:
 
231
                        rpc = RPCProxy(relation)
 
232
 
 
233
                        domain=modelfield.domain_get()
 
234
                        context=modelfield.context_get()
 
235
 
 
236
                        names = rpc.name_search(text, domain, 'ilike', context)
 
237
                        if len(names) == 1:
 
238
                                return True, names[0]
 
239
                        searched = self.search_remote(relation, [x[0] for x in names], domain=domain, context=context)
 
240
                        if searched[0]:
 
241
                                return True, searched
 
242
                        return False, False
 
243
                dia = M2ODialog(relation, id)
 
244
                new_value = dia.run()
 
245
                dia.destroy()
 
246
                if new_value[0]:
 
247
                        return True, new_value[1]
 
248
                else:
 
249
                        return False, False
 
250
        
 
251
        def search_remote(self, relation, ids=[], domain=[], context={}):
 
252
                rpc = RPCProxy(relation)
 
253
 
 
254
                win = win_search(relation, sel_multi=False, ids=ids)
 
255
                found = win.go()
 
256
                if found:
 
257
                        return rpc.name_get([found[0]], context)[0]
 
258
                else:
 
259
                        return False, None
 
260
 
 
261
 
 
262
class O2M(Char):
 
263
        def get_textual_value(self, model):
 
264
                return '( '+str(len(model[self.field_name].internal.models or [])) + ' )'
 
265
 
 
266
        def value_from_text(self, model, text):
 
267
                raise UnsettableColumn('Can not set column of type o2m')
 
268
 
 
269
 
 
270
class M2M(Char):
 
271
        def get_textual_value(self, model):
 
272
                value = model[self.field_name].internal
 
273
                if value:
 
274
                        return '(%s)' % len(value)
 
275
                else:
 
276
                        return '(0)'
 
277
 
 
278
        def value_from_text(self, model, text):
 
279
                raise UnsettableColumn('Can not set column of type m2m')
 
280
 
 
281
 
 
282
class Selection(Char):
 
283
 
 
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)
 
292
 
 
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, '')
 
296
 
 
297
        def value_from_text(self, model, text):
 
298
                selection = model[self.field_name].attrs['selection']
 
299
                for val, txt in selection:
 
300
                        if txt == text:
 
301
                                return val
 
302
                return False
 
303
 
 
304
CELLTYPES = dict(char=Char,
 
305
                                 many2one=M2O,
 
306
                                 date=Date,
 
307
                                 one2many=O2M,
 
308
                                 many2many=M2M,
 
309
                                 selection=Selection,
 
310
                                 float=Float,
 
311
                                 int=Int,
 
312
                                 datetime=Datetime)
 
313
 
 
314
# vim:noexpandtab: