markup must not be translatable
[openerp-client.git] / bin / widget / view / form_gtk / parser.py
blob3b85755f75ab70de0925fb02bf2dc139607ac399
1 # -*- encoding: utf-8 -*-
2 ##############################################################################
4 # Copyright (c) 2004-2008 TINY SPRL. (http://tiny.be) All Rights Reserved.
6 # $Id$
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
13 # Service Company
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 import tools
32 import interface
34 import widget.view.interface
35 from observator import oregistry, Observable
37 import gtk
39 import common
40 import service
41 import rpc
43 import copy
45 import options
48 class Button(Observable):
49 def __init__(self, attrs={}):
50 super(Button, self).__init__()
51 self.attrs = attrs
52 args = {
53 'label': attrs.get('string', 'unknown')
55 self.widget = gtk.Button(**args)
56 if attrs.get('icon', False):
57 try:
58 stock = attrs['icon']
59 icon = gtk.Image()
60 icon.set_from_stock(stock, gtk.ICON_SIZE_BUTTON)
61 self.widget.set_image(icon)
62 except Exception,e:
63 import logging
64 log = logging.getLogger('common')
65 log.warning(_('Wrong icon for the button !'))
66 # self.widget.set_use_stock(True)
67 # self.widget.set_label(args['label'])
69 self.widget.show()
70 self.widget.connect('clicked', self.button_clicked)
72 def hide(self):
73 return self.widget.hide()
75 def show(self):
76 return self.widget.show()
78 def button_clicked(self, widget):
79 model = self.form.screen.current_model
80 self.form.set_value()
81 button_type = self.attrs.get('special', '')
82 if button_type=='cancel':
83 self.form.screen.window.destroy()
84 if 'name' in self.attrs.keys():
85 result = rpc.session.rpc_exec_auth(
86 '/object', 'execute',
87 self.form.screen.name,
88 self.attrs['name'],[], model.context_get())
89 datas = {}
90 obj = service.LocalService('action.main')
91 obj._exec_action(result,datas,context=self.form.screen.context)
92 elif model.validate():
93 id = self.form.screen.save_current()
94 if not self.attrs.get('confirm',False) or \
95 common.sur(self.attrs['confirm']):
96 button_type = self.attrs.get('type', 'workflow')
97 if button_type == 'workflow':
98 #print 'Exec Workflow'
99 result = rpc.session.rpc_exec_auth('/object', 'exec_workflow',
100 self.form.screen.name,
101 self.attrs['name'], id)
102 if type(result)==type({}):
103 if result['type']== 'ir.actions.act_window_close':
104 self.form.screen.window.destroy()
105 else:
106 datas = {}
107 obj = service.LocalService('action.main')
108 obj._exec_action(result,datas)
109 elif button_type == 'object':
110 if not id:
111 return
112 result = rpc.session.rpc_exec_auth(
113 '/object', 'execute',
114 self.form.screen.name,
115 self.attrs['name'],
116 [id], model.context_get()
118 if type(result)==type({}):
119 self.form.screen.window.destroy()
120 datas = {}
121 obj = service.LocalService('action.main')
122 obj._exec_action(result,datas,context=self.form.screen.context)
124 elif button_type == 'action':
125 obj = service.LocalService('action.main')
126 action_id = int(self.attrs['name'])
127 obj.execute(action_id, {'model':self.form.screen.name, 'id': id or False,
128 'ids': id and [id] or [], 'report_type': 'pdf'}, context=self.form.screen.context)
129 else:
130 raise Exception, 'Unallowed button type'
131 self.form.screen.reload()
132 else:
133 self.warn('misc-message', _('Invalid form, correct red fields !'), "red")
134 self.form.screen.display()
138 class StateAwareWidget(object):
139 def __init__(self, widget, states=None):
140 self.widget = widget
141 self.states = states or []
143 def __getattr__(self, a):
144 return self.widget.__getattribute__(a)
146 def state_set(self, state):
147 if (not len(self.states)) or (state in self.states):
148 self.widget.show()
149 else:
150 self.widget.hide()
152 def attrs_set(self, model):
153 sa = hasattr(self.widget, 'attrs') and self.widget.attrs or {}
154 attrs_changes = eval(sa.get('attrs',"{}"))
155 for k,v in attrs_changes.items():
156 for condition in v:
157 result = tools.calc_condition(self,model,condition)
158 if result:
159 if k=='invisible':
160 self.widget.hide()
161 elif k=='readonly':
162 self.widget.set_sensitive(False)
163 else:
164 self.widget.set_sensitive(False and sa.get('readonly',False))
167 class _container(object):
168 def __init__(self, tooltips):
169 self.cont = []
170 self.col = []
171 self.sg = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
172 self.tooltips = tooltips
173 self.trans_box = []
174 self.trans_box_label = []
176 def new(self, col=4):
177 table = gtk.Table(1, col)
178 table.set_homogeneous(False)
179 table.set_col_spacings(3)
180 table.set_row_spacings(0)
181 table.set_border_width(1)
182 self.cont.append( (table, 0, 0) )
183 self.col.append( col )
185 def get(self):
186 return self.cont[-1][0]
188 def pop(self):
189 (table, x, y) = self.cont.pop()
190 self.col.pop()
191 return table
193 def newline(self):
194 (table, x, y) = self.cont[-1]
195 if x>0:
196 self.cont[-1] = (table, 0, y+1)
197 table.resize(y+1,self.col[-1])
199 def wid_add(self, widget, name=None, expand=False, ypadding=2, rowspan=1,
200 colspan=1, translate=False, fname=None, help=False, fill=False):
201 (table, x, y) = self.cont[-1]
202 if colspan>self.col[-1]:
203 colspan=self.col[-1]
204 a = name and 1 or 0
205 if colspan+x+a>self.col[-1]:
206 self.newline()
207 (table, x, y) = self.cont[-1]
208 yopt = False
209 if expand:
210 yopt = yopt | gtk.EXPAND
211 if fill:
212 yopt = yopt | gtk.FILL
213 if colspan == 1 and a == 1:
214 colspan = 2
215 if name:
216 label = gtk.Label(name)
217 eb = gtk.EventBox()
218 eb.set_events(gtk.gdk.BUTTON_PRESS_MASK)
219 self.trans_box_label.append((eb, name, fname))
220 eb.add(label)
221 if help:
222 self.tooltips.set_tip(eb, help)
223 self.tooltips.enable()
224 label.set_markup("<sup><span foreground=\"darkgreen\">?</span></sup>"+name.replace('&','&amp;').replace('<','&lt;').replace('>','&gt;'))
225 eb.show()
226 if '_' in name:
227 label.set_text_with_mnemonic(name)
228 label.set_mnemonic_widget(widget)
229 label.set_alignment(1.0, 0.5)
230 table.attach(eb, x, x+1, y, y+rowspan, yoptions=yopt,
231 xoptions=gtk.FILL, ypadding=ypadding, xpadding=2)
232 hbox = widget
233 hbox.show_all()
234 if translate:
235 hbox = gtk.HBox(spacing=3)
236 hbox.pack_start(widget)
237 img = gtk.Image()
238 img.set_from_stock('terp-translate', gtk.ICON_SIZE_MENU)
239 ebox = gtk.EventBox()
240 ebox.set_events(gtk.gdk.BUTTON_PRESS_MASK)
241 self.trans_box.append((ebox, name, fname, widget))
243 ebox.add(img)
244 hbox.pack_start(ebox, fill=False, expand=False)
245 hbox.show_all()
246 table.attach(hbox, x+a, x+colspan, y, y+rowspan, yoptions=yopt,
247 ypadding=ypadding, xpadding=2)
248 self.cont[-1] = (table, x+colspan, y)
249 wid_list = table.get_children()
250 wid_list.reverse()
251 table.set_focus_chain(wid_list)
253 class parser_form(widget.view.interface.parser_interface):
254 def parse(self, model, root_node, fields, notebook=None, paned=None, tooltips=None):
255 dict_widget = {}
256 saw_list = [] # state aware widget list
257 attrs = tools.node_attributes(root_node)
258 on_write = attrs.get('on_write', '')
259 if not tooltips:
260 self.tooltips = gtk.Tooltips()
261 else:
262 self.tooltips = tooltips
263 container = _container(self.tooltips)
264 container.new(col=int(attrs.get('col', 4)))
265 self.container = container
267 if not self.title:
268 attrs = tools.node_attributes(root_node)
269 self.title = attrs.get('string', 'Unknown')
271 for node in root_node.childNodes:
272 if not node.nodeType==node.ELEMENT_NODE:
273 continue
274 attrs = tools.node_attributes(node)
275 if node.localName=='image':
276 icon = gtk.Image()
277 icon.set_from_stock(attrs['name'], gtk.ICON_SIZE_DIALOG)
278 container.wid_add(icon,colspan=int(attrs.get('colspan',1)),expand=int(attrs.get('expand',0)), ypadding=10, help=attrs.get('help', False), fill=int(attrs.get('fill', 0)))
279 elif node.localName=='separator':
280 vbox = gtk.VBox()
281 if 'string' in attrs:
282 text = attrs.get('string', 'No String Attr.')
283 l = gtk.Label('<b>'+(text.replace('&','&amp;').replace('<','&lt;').replace('>','&gt;'))+'</b>')
284 l.set_use_markup(True)
285 l.set_alignment(0.0, 0.5)
286 eb = gtk.EventBox()
287 eb.set_events(gtk.gdk.BUTTON_PRESS_MASK)
288 eb.add(l)
289 container.trans_box_label.append((eb, text, None))
290 vbox.pack_start(eb)
291 vbox.pack_start(gtk.HSeparator())
292 container.wid_add(vbox,colspan=int(attrs.get('colspan',1)),expand=int(attrs.get('expand',0)), ypadding=10, help=attrs.get('help', False), fill=int(attrs.get('fill', 0)))
293 elif node.localName=='label':
294 text = attrs.get('string', '')
295 if not text:
296 for node in node.childNodes:
297 if node.nodeType == node.TEXT_NODE:
298 text += node.data
299 else:
300 text += node.toxml()
301 label = gtk.Label(text)
302 label.set_use_markup(True)
303 if 'align' in attrs:
304 try:
305 label.set_alignment(float(attrs['align'] or 0.0), 0.5)
306 except:
307 pass
308 if 'angle' not in attrs:
309 label.set_line_wrap(True)
310 label.set_angle(int(attrs.get('angle', 0)))
311 eb = gtk.EventBox()
312 eb.set_events(gtk.gdk.BUTTON_PRESS_MASK)
313 eb.add(label)
314 container.trans_box_label.append((eb, text, None))
315 container.wid_add(eb, colspan=int(attrs.get('colspan', 1)), expand=False, help=attrs.get('help', False), fill=int(attrs.get('fill', 0)))
317 elif node.localName=='newline':
318 container.newline()
320 elif node.localName=='button':
321 button = Button(attrs)
322 states = [e for e in attrs.get('states','').split(',') if e]
323 saw_list.append(StateAwareWidget(button, states))
324 container.wid_add(button.widget, colspan=int(attrs.get('colspan', 1)), help=attrs.get('help', False))
326 elif node.localName=='notebook':
327 nb = gtk.Notebook()
328 if attrs and 'tabpos' in attrs:
329 pos = {'up':gtk.POS_TOP,
330 'down':gtk.POS_BOTTOM,
331 'left':gtk.POS_LEFT,
332 'right':gtk.POS_RIGHT
333 }[attrs['tabpos']]
334 else:
335 if options.options['client.form_tab'] == 'top':
336 pos = gtk.POS_TOP
337 elif options.options['client.form_tab'] == 'left':
338 pos = gtk.POS_LEFT
339 elif options.options['client.form_tab'] == 'right':
340 pos = gtk.POS_RIGHT
341 elif options.options['client.form_tab'] == 'bottom':
342 pos = gtk.POS_BOTTOM
343 nb.set_tab_pos(pos)
344 nb.set_border_width(3)
345 container.wid_add(nb, colspan=attrs.get('colspan', 3), expand=True, fill=True )
346 _, widgets, saws, on_write = self.parse(model, node, fields, nb, tooltips=self.tooltips)
347 saw_list += saws
348 dict_widget.update(widgets)
350 elif node.localName=='page':
351 if attrs and 'angle' in attrs:
352 angle = int(attrs['angle'])
353 else:
354 angle = int(options.options['client.form_tab_orientation'])
355 l = gtk.Label(attrs.get('string','No String Attr.'))
356 l.attrs=attrs.copy()
357 l.set_angle(angle)
358 widget, widgets, saws, on_write = self.parse(model, node, fields, notebook, tooltips=self.tooltips)
359 saw_list += saws
360 dict_widget.update(widgets)
361 notebook.append_page(widget, l)
363 elif node.localName=='field':
364 name = str(attrs['name'])
365 del attrs['name']
366 type = attrs.get('widget', fields[name]['type'])
367 fields[name].update(attrs)
368 fields[name]['model']=model
369 if not type in widgets_type:
370 continue
371 if attrs.get('invisible', False):
372 visval = eval(attrs['invisible'], {'context':self.screen.context})
373 if visval:
374 continue
376 fields[name]['name'] = name
377 if 'saves' in attrs:
378 fields[name]['saves'] = attrs['saves']
380 if 'filename' in attrs:
381 fields[name]['filename'] = attrs['filename']
383 widget_act = widgets_type[type][0](self.window, self.parent, model, fields[name])
384 label = None
385 if not int(attrs.get('nolabel', 0)):
386 # TODO space before ':' depends of lang (ex: english no space)
387 if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL:
388 label = ': '+fields[name]['string']
389 else:
390 label = fields[name]['string']+' :'
391 dict_widget[name] = widget_act
392 size = int(attrs.get('colspan', widgets_type[ type ][1]))
393 expand = widgets_type[ type ][2]
394 fill = widgets_type[ type ][3]
395 hlp = fields[name].get('help', attrs.get('help', False))
396 if attrs.get('height', False) or attrs.get('width', False):
397 widget_act.widget.set_size_request(
398 int(attrs.get('width', -1)), int(attrs.get('height', -1)))
399 container.wid_add(widget_act.widget, label, expand, translate=fields[name].get('translate',False), colspan=size, fname=name, help=hlp, fill=fill)
401 elif node.localName=='group':
402 frame = gtk.Frame(attrs.get('string', None))
403 frame.attrs=attrs
404 frame.set_border_width(0)
405 states = [e for e in attrs.get('states','').split(',') if e]
406 saw_list.append(StateAwareWidget(frame, states))
408 container.wid_add(frame, colspan=int(attrs.get('colspan', 1)), expand=int(attrs.get('expand',0)), rowspan=int(attrs.get('rowspan', 1)), ypadding=0, fill=int(attrs.get('fill', 1)))
409 container.new(int(attrs.get('col',4)))
411 widget, widgets, saws, on_write = self.parse(model, node, fields, tooltips=self.tooltips)
412 dict_widget.update(widgets)
413 saw_list += saws
414 frame.add(widget)
415 if not attrs.get('string', None):
416 frame.set_shadow_type(gtk.SHADOW_NONE)
417 container.get().set_border_width(0)
418 container.pop()
419 elif node.localName=='hpaned':
420 hp = gtk.HPaned()
421 container.wid_add(hp, colspan=int(attrs.get('colspan', 4)), expand=True, fill=True)
422 _, widgets, saws, on_write = self.parse(model, node, fields, paned=hp, tooltips=self.tooltips)
423 saw_list += saws
424 dict_widget.update(widgets)
425 #if 'position' in attrs:
426 # hp.set_position(int(attrs['position']))
427 elif node.localName=='vpaned':
428 hp = gtk.VPaned()
429 container.wid_add(hp, colspan=int(attrs.get('colspan', 4)), expand=True, fill=True)
430 _, widgets, saws, on_write = self.parse(model, node, fields, paned=hp, tooltips=self.tooltips)
431 saw_list += saws
432 dict_widget.update(widgets)
433 if 'position' in attrs:
434 hp.set_position(int(attrs['position']))
435 elif node.localName=='child1':
436 widget, widgets, saws, on_write = self.parse(model, node, fields, paned=paned, tooltips=self.tooltips)
437 saw_list += saws
438 dict_widget.update(widgets)
439 paned.pack1(widget, resize=True, shrink=True)
440 elif node.localName=='child2':
441 widget, widgets, saws, on_write = self.parse(model, node, fields, paned=paned, tooltips=self.tooltips)
442 saw_list += saws
443 dict_widget.update(widgets)
444 paned.pack2(widget, resize=True, shrink=True)
445 elif node.localName=='action':
446 from action import action
447 name = str(attrs['name'])
448 widget_act = action(self.window, self.parent, model, attrs)
449 dict_widget[name] = widget_act
450 container.wid_add(widget_act.widget, colspan=int(attrs.get('colspan', 3)), expand=True, fill=True)
451 for (ebox,src,name,widget) in container.trans_box:
452 ebox.connect('button_press_event',self.translate, model, name, src, widget)
453 for (ebox,src,name) in container.trans_box_label:
454 ebox.connect('button_press_event', self.translate_label, model, name, src)
455 return container.pop(), dict_widget, saw_list, on_write
457 def translate(self, widget, event, model, name, src, widget_entry):
458 id = self.screen.current_model.id
459 if not id:
460 common.message(
461 _('You need to save resource before adding translations!'),
462 parent=self.window)
463 return False
464 id = self.screen.current_model.save(reload=False)
465 uid = rpc.session.uid
467 lang_ids = rpc.session.rpc_exec_auth('/object', 'execute', 'res.lang',
468 'search', [('translatable','=','1')])
470 if not lang_ids:
471 common.message(_('No other language available!'),
472 parent=self.window)
473 return False
474 langs = rpc.session.rpc_exec_auth('/object', 'execute', 'res.lang',
475 'read', lang_ids, ['code', 'name'])
477 code = rpc.session.context.get('lang', 'en_US')
479 #change 'en' to false for context
480 def adapt_context(val):
481 if val == 'en_US':
482 return False
483 else:
484 return val
486 #widget accessor functions
487 def value_get(widget):
488 if type(widget) == type(gtk.Entry()):
489 return widget.get_text()
490 elif type(widget.child) == type(gtk.TextView()):
491 buffer = widget.child.get_buffer()
492 iter_start = buffer.get_start_iter()
493 iter_end = buffer.get_end_iter()
494 return buffer.get_text(iter_start,iter_end,False)
495 else:
496 return None
498 def value_set(widget, value):
499 if type(widget) == type(gtk.Entry()):
500 widget.set_text(value)
501 elif type(widget.child) == type(gtk.TextView()):
502 if value==False:
503 value=''
504 buffer = widget.child.get_buffer()
505 buffer.delete(buffer.get_start_iter(), buffer.get_end_iter())
506 iter_start = buffer.get_start_iter()
507 buffer.insert(iter_start, value)
509 def widget_duplicate(widget):
510 if type(widget) == type(gtk.Entry()):
511 entry = gtk.Entry()
512 entry.set_property('activates_default', True)
513 entry.set_max_length(widget.get_max_length())
514 entry.set_width_chars(widget.get_width_chars())
515 return entry, gtk.FILL
516 elif type(widget.child) == type(gtk.TextView()):
517 tv = gtk.TextView()
518 tv.set_wrap_mode(gtk.WRAP_WORD)
519 sw = gtk.ScrolledWindow()
520 sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
521 sw.set_shadow_type(gtk.SHADOW_NONE)
522 sw.set_size_request(-1, 80)
523 sw.add(tv)
524 tv.set_accepts_tab(False)
525 return sw, gtk.FILL | gtk.EXPAND
526 else:
527 return None, False
530 win = gtk.Dialog(_('Add Translation'), self.window,
531 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
532 win.vbox.set_spacing(5)
533 win.set_property('default-width', 600)
534 win.set_property('default-height', 400)
535 win.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
536 win.set_icon(common.TINYERP_ICON)
538 accel_group = gtk.AccelGroup()
539 win.add_accel_group(accel_group)
541 but_cancel = win.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
542 but_cancel.add_accelerator('clicked', accel_group, gtk.keysyms.Escape,
543 gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
544 but_ok = win.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
545 but_ok.add_accelerator('clicked', accel_group, gtk.keysyms.Return,
546 gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
548 vbox = gtk.VBox(spacing=5)
550 entries_list = []
551 table = gtk.Table(len(langs), 2)
552 table.set_homogeneous(False)
553 table.set_col_spacings(3)
554 table.set_row_spacings(0)
555 table.set_border_width(1)
556 i = 0
557 for lang in langs:
558 context = copy.copy(rpc.session.context)
559 context['lang'] = adapt_context(lang['code'])
560 val = rpc.session.rpc_exec_auth('/object', 'execute', model,
561 'read', [id], [name], context)
562 val = val[0]
563 #TODO space before ':' depends of lang (ex: english no space)
564 if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL:
565 label = gtk.Label(': ' + lang['name'])
566 else:
567 label = gtk.Label(lang['name'] + ' :')
568 label.set_alignment(1.0, 0.5)
569 (entry, yoptions) = widget_duplicate(widget_entry)
571 hbox = gtk.HBox(homogeneous=False)
572 if code == lang['code']:
573 value_set(entry,value_get(widget_entry))
574 else:
575 value_set(entry,val[name])
577 entries_list.append((val['id'], lang['code'], entry))
578 table.attach(label, 0, 1, i, i+1, yoptions=False, xoptions=gtk.FILL,
579 ypadding=2, xpadding=5)
580 table.attach(entry, 1, 2, i, i+1, yoptions=yoptions,
581 ypadding=2, xpadding=5)
582 i += 1
584 vbox.pack_start(table)
585 vp = gtk.Viewport()
586 vp.set_shadow_type(gtk.SHADOW_NONE)
587 vp.add(vbox)
588 sv = gtk.ScrolledWindow()
589 sv.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC )
590 sv.set_shadow_type(gtk.SHADOW_NONE)
591 sv.add(vp)
592 win.vbox.add(sv)
593 win.show_all()
595 ok = False
596 data = []
597 while not ok:
598 response = win.run()
599 ok = True
600 if response == gtk.RESPONSE_OK:
601 to_save = map(lambda x : (x[0], x[1], value_get(x[2])),
602 entries_list)
603 while to_save != []:
604 new_val = {}
605 new_val['id'],new_val['code'], new_val['value'] = to_save.pop()
606 #update form field
607 if new_val['code'] == code:
608 value_set(widget_entry, new_val['value'])
609 context = copy.copy(rpc.session.context)
610 context['lang'] = adapt_context(new_val['code'])
611 rpc.session.rpc_exec_auth('/object', 'execute', model,
612 'write', [id], {str(name): new_val['value']},
613 context)
614 if response == gtk.RESPONSE_CANCEL:
615 self.window.present()
616 win.destroy()
617 return
618 self.screen.current_model.reload()
619 self.window.present()
620 win.destroy()
621 return True
623 def translate_label(self, widget, event, model, name, src):
624 def callback_label(self, widget, event, model, name, src, window=None):
625 lang_ids = rpc.session.rpc_exec_auth('/object', 'execute',
626 'res.lang', 'search', [('translatable', '=', '1')])
627 if not lang_ids:
628 common.message(_('No other language available!'),
629 parent=window)
630 return False
631 langs = rpc.session.rpc_exec_auth('/object', 'execute', 'res.lang',
632 'read', lang_ids, ['code', 'name'])
634 win = gtk.Dialog(_('Add Translation'), window,
635 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
636 win.vbox.set_spacing(5)
637 win.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
638 win.set_icon(common.TINYERP_ICON)
639 vbox = gtk.VBox(spacing=5)
641 entries_list = []
642 for lang in langs:
643 code=lang['code']
644 val = rpc.session.rpc_exec_auth('/object', 'execute', model,
645 'read_string', False, [code], [name])
646 if val and code in val:
647 val = val[code]
648 else:
649 val={'code': code, 'name': src}
650 label = gtk.Label(lang['name'])
651 entry = gtk.Entry()
652 entry.set_text(val[name])
653 entries_list.append((code, entry))
654 hbox = gtk.HBox(homogeneous=True)
655 hbox.pack_start(label, expand=False, fill=False)
656 hbox.pack_start(entry, expand=True, fill=True)
657 vbox.pack_start(hbox, expand=False, fill=True)
658 vp = gtk.Viewport()
659 vp.set_shadow_type(gtk.SHADOW_NONE)
660 vp.add(vbox)
661 sv = gtk.ScrolledWindow()
662 sv.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC )
663 sv.set_shadow_type(gtk.SHADOW_NONE)
664 sv.add(vp)
665 win.vbox.add(sv)
666 win.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
667 win.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
668 win.resize(400,200)
669 win.show_all()
670 res = win.run()
671 if res == gtk.RESPONSE_OK:
672 to_save = map(lambda x: (x[0], x[1].get_text()), entries_list)
673 while to_save:
674 code, val = to_save.pop()
675 rpc.session.rpc_exec_auth('/object', 'execute', model,
676 'write_string', False, [code], {name: val})
677 window.present()
678 win.destroy()
679 return res
681 def callback_view(self, widget, event, model, src, window=None):
682 lang_ids = rpc.session.rpc_exec_auth('/object', 'execute',
683 'res.lang', 'search', [('translatable', '=', '1')])
684 if not lang_ids:
685 common.message(_('No other language available!'),
686 parent=window)
687 return False
688 langs = rpc.session.rpc_exec_auth('/object', 'execute', 'res.lang',
689 'read', lang_ids, ['code', 'name'])
691 win = gtk.Dialog(_('Add Translation'), window,
692 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
693 win.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
694 win.set_icon(common.TINYERP_ICON)
695 win.vbox.set_spacing(5)
696 vbox = gtk.VBox(spacing=5)
698 entries_list = []
699 for lang in langs:
700 code=lang['code']
701 view_item_ids = rpc.session.rpc_exec_auth('/object', 'execute',
702 'ir.translation', 'search', [
703 ('name', '=', model),
704 ('type', '=', 'view'),
705 ('lang', '=', code),
707 view_items = rpc.session.rpc_exec_auth('/object', 'execute',
708 'ir.translation', 'read', view_item_ids,
709 ['src', 'value'])
710 label = gtk.Label(lang['name'])
711 vbox.pack_start(label, expand=False, fill=True)
712 for val in view_items:
713 label = gtk.Label(val['src'])
714 entry = gtk.Entry()
715 entry.set_text(val['value'])
716 entries_list.append((val['id'], entry))
717 hbox = gtk.HBox(homogeneous=True)
718 hbox.pack_start(label, expand=False, fill=False)
719 hbox.pack_start(entry, expand=True, fill=True)
720 vbox.pack_start(hbox, expand=False, fill=True)
721 vp = gtk.Viewport()
722 vp.set_shadow_type(gtk.SHADOW_NONE)
723 vp.add(vbox)
724 sv = gtk.ScrolledWindow()
725 sv.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC )
726 sv.set_shadow_type(gtk.SHADOW_NONE)
727 sv.add(vp)
728 win.vbox.add(sv)
729 win.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
730 win.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
731 win.resize(400,200)
732 win.show_all()
733 res = win.run()
734 if res == gtk.RESPONSE_OK:
735 to_save = map(lambda x: (x[0], x[1].get_text()), entries_list)
736 while to_save:
737 id, val = to_save.pop()
738 rpc.session.rpc_exec_auth('/object', 'execute',
739 'ir.translation', 'write', [id], {'value': val})
740 window.present()
741 win.destroy()
742 return res
743 if event.button != 3:
744 return
745 menu = gtk.Menu()
746 if name:
747 item = gtk.ImageMenuItem(_('Translate label'))
748 item.connect("activate", callback_label, widget, event, model,
749 name, src, self.window)
750 item.set_sensitive(1)
751 item.show()
752 menu.append(item)
753 item = gtk.ImageMenuItem(_('Translate view'))
754 item.connect("activate", callback_view, widget, event, model, src,
755 self.window)
756 item.set_sensitive(1)
757 item.show()
758 menu.append(item)
759 menu.popup(None,None,None,event.button,event.time)
760 return True
762 import float_time
763 import calendar
764 import spinbutton
765 import spinint
766 import char
767 import checkbox
768 import button
769 import reference
770 import binary
771 import textbox
772 import textbox_tag
773 #import one2many
774 import many2many
775 import many2one
776 import selection
777 import one2many_list
778 import picture
779 import url
780 import image
782 import progressbar
784 widgets_type = {
785 'date': (calendar.calendar, 1, False, False),
786 'time': (calendar.stime, 1, False, False),
787 'datetime': (calendar.datetime, 1, False, False),
788 'float': (spinbutton.spinbutton, 1, False, False),
789 'integer': (spinint.spinint, 1, False, False),
790 'selection': (selection.selection, 1, False, False),
791 'char': (char.char, 1, False, False),
792 'float_time': (float_time.float_time, 1, False, False),
793 'boolean': (checkbox.checkbox, 1, False, False),
794 'button': (button.button, 1, False, False),
795 'reference': (reference.reference, 1, False, False),
796 'binary': (binary.wid_binary, 1, False, False),
797 'picture': (picture.wid_picture, 1, False, False),
798 'text': (textbox.textbox, 1, True, True),
799 'text_tag': (textbox_tag.textbox_tag, 1, True, True),
800 'one2many': (one2many_list.one2many_list, 1, True, True),
801 'one2many_form': (one2many_list.one2many_list, 1, True, True),
802 'one2many_list': (one2many_list.one2many_list, 1, True, True),
803 'many2many': (many2many.many2many, 1, True, True),
804 'many2one': (many2one.many2one, 1, False, False),
805 'email' : (url.email, 1, False, False),
806 'url' : (url.url, 1, False, False),
807 'callto' : (url.callto, 1, False, False),
808 'sip' : (url.sip, 1, False, False),
809 'image' : (image.image_wid, 1, False, False),
810 'uri' : (url.uri, 1, False, False),
811 'progressbar' : (progressbar.progressbar, 1, False, False),
815 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: