~ubuntu-branches/ubuntu/trusty/openerp-client/trusty

« back to all changes in this revision

Viewing changes to bin/widget/view/form_gtk/many2one.py

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann
  • Date: 2008-12-07 20:17:00 UTC
  • Revision ID: james.westby@ubuntu.com-20081207201700-a875pic3sd7xkoru
Tags: upstream-5.0.0~alpha
ImportĀ upstreamĀ versionĀ 5.0.0~alpha

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- encoding: utf-8 -*-
 
2
##############################################################################
 
3
#
 
4
#    OpenERP, Open Source Management Solution   
 
5
#    Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
 
6
#    $Id$
 
7
#
 
8
#    This program is free software: you can redistribute it and/or modify
 
9
#    it under the terms of the GNU General Public License as published by
 
10
#    the Free Software Foundation, either version 3 of the License, or
 
11
#    (at your option) any later version.
 
12
#
 
13
#    This program is distributed in the hope that it will be useful,
 
14
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
#    GNU General Public License for more details.
 
17
#
 
18
#    You should have received a copy of the GNU General Public License
 
19
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
20
#
 
21
##############################################################################
 
22
 
 
23
import gobject
 
24
import gtk
 
25
import copy
 
26
 
 
27
import gettext
 
28
 
 
29
import interface
 
30
import wid_common
 
31
import common
 
32
 
 
33
import widget
 
34
from widget.screen import Screen
 
35
 
 
36
from modules.gui.window.win_search import win_search
 
37
import rpc
 
38
 
 
39
import service
 
40
 
 
41
 
 
42
class dialog(object):
 
43
    def __init__(self, model, id=None, attrs=None ,domain=None, context=None, window=None, view_ids=None,target=False,view_type=['form']):
 
44
        if attrs is None:
 
45
            attrs = {}
 
46
        if domain is None:
 
47
            domain = []
 
48
        if context is None:
 
49
            context = {}
 
50
 
 
51
        if not window:
 
52
            window = service.LocalService('gui.main').window
 
53
 
 
54
        self.dia = gtk.Dialog(_('OpenERP - Link'), window,
 
55
                gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT)
 
56
        self.window = window
 
57
        if ('string' in attrs) and attrs['string']:
 
58
            self.dia.set_title(self.dia.get_title() + ' - ' + attrs['string'])
 
59
        if not target:
 
60
            self.dia.set_property('default-width', 760)
 
61
            self.dia.set_property('default-height', 500)
 
62
            self.dia.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
 
63
            self.dia.set_icon(common.OPENERP_ICON)
 
64
 
 
65
            self.accel_group = gtk.AccelGroup()
 
66
            self.dia.add_accel_group(self.accel_group)
 
67
 
 
68
            self.but_cancel = self.dia.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
 
69
            self.but_cancel.add_accelerator('clicked', self.accel_group, gtk.keysyms.Escape, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
 
70
 
 
71
            self.but_ok = self.dia.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
 
72
            self.but_ok.add_accelerator('clicked', self.accel_group, gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
 
73
 
 
74
        scroll = gtk.ScrolledWindow()
 
75
        scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
 
76
        scroll.set_placement(gtk.CORNER_TOP_LEFT)
 
77
        scroll.set_shadow_type(gtk.SHADOW_NONE)
 
78
        self.dia.vbox.pack_start(scroll, expand=True, fill=True)
 
79
 
 
80
        vp = gtk.Viewport()
 
81
        vp.set_shadow_type(gtk.SHADOW_NONE)
 
82
        scroll.add(vp)
 
83
        self.screen = Screen(model, view_ids=view_ids, domain=domain, context=context, window=self.dia, view_type=view_type)
 
84
        if id:
 
85
            self.screen.load([id])
 
86
        else:
 
87
            self.screen.new()
 
88
        vp.add(self.screen.widget)
 
89
 
 
90
        x,y = self.screen.screen_container.size_get()
 
91
        width, height = window.get_size()
 
92
        if not target:
 
93
            vp.set_size_request(min(width - 20, x + 20),min(height - 60, y + 25))
 
94
        else:
 
95
            vp.set_size_request(x,y)
 
96
        self.dia.show_all()
 
97
        self.screen.display()
 
98
 
 
99
    def run(self, datas={}):
 
100
        while True:
 
101
            res = self.dia.run()
 
102
            if res==gtk.RESPONSE_OK:
 
103
                if self.screen.current_model.validate() and self.screen.save_current():
 
104
                    return (True, self.screen.current_model.name_get())
 
105
                else:
 
106
                    self.screen.display()
 
107
            else:
 
108
                break
 
109
        return (False, False)
 
110
 
 
111
    def destroy(self):
 
112
        self.window.present()
 
113
        self.dia.destroy()
 
114
 
 
115
class many2one(interface.widget_interface):
 
116
    def __init__(self, window, parent, model, attrs={}):
 
117
        interface.widget_interface.__init__(self, window, parent, model, attrs)
 
118
 
 
119
        self.widget = gtk.HBox(spacing=3)
 
120
        self.widget.set_property('sensitive', True)
 
121
        self.widget.connect('focus-in-event', lambda x,y: self._focus_in())
 
122
        self.widget.connect('focus-out-event', lambda x,y: self._focus_out())
 
123
 
 
124
        self.wid_text = gtk.Entry()
 
125
        self.wid_text.set_property('width-chars', 13)
 
126
        self.wid_text.connect('key_press_event', self.sig_key_press)
 
127
        self.wid_text.connect('button_press_event', self._menu_open)
 
128
        self.wid_text.connect_after('changed', self.sig_changed)
 
129
        self.wid_text.connect_after('activate', self.sig_activate)
 
130
        self.wid_text_focus_out_id = self.wid_text.connect_after('focus-out-event', self.sig_focus_out, True)
 
131
        self.widget.pack_start(self.wid_text, expand=True, fill=True)
 
132
 
 
133
        self.but_find = gtk.Button()
 
134
        img_find = gtk.Image()
 
135
        img_find.set_from_stock('gtk-find',gtk.ICON_SIZE_BUTTON)
 
136
        self.but_find.set_image(img_find)
 
137
        self.but_find.set_relief(gtk.RELIEF_NONE)
 
138
        self.but_find.connect('clicked', self.sig_find)
 
139
        self.but_find.set_alignment(0.5, 0.5)
 
140
        self.but_find.set_property('can-focus', False)
 
141
 
 
142
        self.tooltips = gtk.Tooltips()
 
143
        self.tooltips.set_tip(self.but_find, _('Select a record'))
 
144
        self.tooltips.enable()
 
145
 
 
146
 
 
147
        self.but_open = gtk.Button()
 
148
        img_open = gtk.Image()
 
149
        img_open.set_from_stock('gtk-open',gtk.ICON_SIZE_BUTTON)
 
150
        self.but_open.set_image(img_open)
 
151
        self.but_open.set_relief(gtk.RELIEF_NONE)
 
152
        self.but_open.connect('clicked', self.sig_edit)
 
153
        self.but_open.set_alignment(0.5, 0.5)
 
154
        self.but_open.set_property('can-focus', False)
 
155
 
 
156
        self.tooltips = gtk.Tooltips()
 
157
        self.tooltips.set_tip(self.but_find, _('Open this record'))
 
158
        self.tooltips.enable()
 
159
 
 
160
        self.widget.pack_start(self.but_open, padding=2, expand=False, fill=False)
 
161
        self.widget.pack_start(self.but_find, padding=2, expand=False, fill=False)
 
162
 
 
163
        self.ok = True
 
164
        self._readonly = False
 
165
        self.model_type = attrs['relation']
 
166
        self._menu_loaded = False
 
167
        self._menu_entries.append((None, None, None))
 
168
        self._menu_entries.append((_('Action'), lambda x: self.click_and_action('client_action_multi'),0))
 
169
        self._menu_entries.append((_('Report'), lambda x: self.click_and_action('client_print_multi'),0))
 
170
 
 
171
        if attrs.get('completion',False):
 
172
            ids = rpc.session.rpc_exec_auth('/object', 'execute', self.attrs['relation'], 'name_search', '', [], 'ilike', {})
 
173
            if ids:
 
174
                self.load_completion(ids,attrs)
 
175
 
 
176
    def load_completion(self,ids,attrs):
 
177
        self.completion = gtk.EntryCompletion()
 
178
        self.completion.set_match_func(self.match_func, None)
 
179
        self.completion.connect("match-selected", self.on_completion_match)
 
180
        self.wid_text.set_completion(self.completion)
 
181
        self.liststore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
 
182
        self.completion.set_model(self.liststore)
 
183
        self.completion.set_text_column(0)
 
184
        for i,word in enumerate(ids):
 
185
            if word[1][0] == '[':
 
186
                i = word[1].find(']')
 
187
                s = word[1][1:i]
 
188
                s2 = word[1][i+2:]
 
189
                self.liststore.append([("%s %s" % (s,s2)),s2])
 
190
            else:
 
191
                self.liststore.append([word[1],word[1]])
 
192
 
 
193
    def match_func(self, completion, key_string, iter, data):
 
194
        model = self.completion.get_model()
 
195
        modelstr = model[iter][0].lower()
 
196
        return modelstr.startswith(key_string)
 
197
 
 
198
    def on_completion_match(self, completion, model, iter):
 
199
        name = model[iter][1]
 
200
        domain = self._view.modelfield.domain_get(self._view.model)
 
201
        context = self._view.modelfield.context_get(self._view.model)
 
202
        ids = rpc.session.rpc_exec_auth('/object', 'execute',
 
203
                self.attrs['relation'], 'name_search', name, domain, 'ilike',
 
204
                context)
 
205
        if len(ids)==1:
 
206
            self._view.modelfield.set_client(self._view.model, ids[0])
 
207
            self.display(self._view.model, self._view.modelfield)
 
208
            self.ok = True
 
209
        else:
 
210
            win = win_search(self.attrs['relation'], sel_multi=False,
 
211
                    ids=map(lambda x: x[0], ids), context=context,
 
212
                    domain=domain, window=self._window)
 
213
            ids = win.go()
 
214
            if ids:
 
215
                name = rpc.session.rpc_exec_auth('/object', 'execute',
 
216
                        self.attrs['relation'], 'name_get', [ids[0]],
 
217
                        rpc.session.context)[0]
 
218
                self._view.modelfield.set_client(self._view.model, name)
 
219
        return True
 
220
 
 
221
    def _readonly_set(self, value):
 
222
        self._readonly = value
 
223
        self.wid_text.set_editable(not value)
 
224
        #self.but_new.set_sensitive(not value)
 
225
 
 
226
    def _color_widget(self):
 
227
        return self.wid_text
 
228
 
 
229
    def _menu_sig_pref(self, obj):
 
230
        self._menu_sig_default_set()
 
231
 
 
232
    def _menu_sig_default(self, obj):
 
233
        res = rpc.session.rpc_exec_auth('/object', 'execute', self.attrs['model'], 'default_get', [self.attrs['name']])
 
234
 
 
235
    def sig_find(self, widget, event=None, leave=False):
 
236
        self.ok = False
 
237
        self.wid_text.disconnect(self.wid_text_focus_out_id)
 
238
        if not self._readonly:
 
239
            domain = self._view.modelfield.domain_get(self._view.model)
 
240
            context = self._view.modelfield.context_get(self._view.model)
 
241
            self.wid_text.grab_focus()
 
242
 
 
243
            ids = rpc.session.rpc_exec_auth('/object', 'execute', self.attrs['relation'], 'name_search', leave and self.wid_text.get_text() or '', domain, 'ilike', context)
 
244
            if (len(ids)==1) and leave:
 
245
                self._view.modelfield.set_client(self._view.model, ids[0],
 
246
                        force_change=True)
 
247
                self.wid_text_focus_out_id = self.wid_text.connect_after('focus-out-event', self.sig_focus_out, True)
 
248
                self.display(self._view.model, self._view.modelfield)
 
249
                self.ok = True
 
250
                return True
 
251
 
 
252
            win = win_search(self.attrs['relation'], sel_multi=False, ids=map(lambda x: x[0], ids), context=context, domain=domain, parent=self._window)
 
253
            ids = win.go()
 
254
            if ids:
 
255
                name = rpc.session.rpc_exec_auth('/object', 'execute', self.attrs['relation'], 'name_get', [ids[0]], rpc.session.context)[0]
 
256
                self._view.modelfield.set_client(self._view.model, name,
 
257
                        force_change=True)
 
258
        self.wid_text_focus_out_id = self.wid_text.connect_after('focus-out-event', self.sig_focus_out, True)
 
259
        self.display(self._view.model, self._view.modelfield)
 
260
        self.ok=True
 
261
 
 
262
    def sig_edit(self, widget, event=None, leave=False):
 
263
        self.ok = False
 
264
        self.wid_text.disconnect(self.wid_text_focus_out_id)
 
265
        if not leave:
 
266
            domain = self._view.modelfield.domain_get(self._view.model)
 
267
            context = self._view.modelfield.context_get(self._view.model)
 
268
            dia = dialog(self.attrs['relation'], self._view.modelfield.get(self._view.model), attrs=self.attrs, window=self._window, domain=domain, context=context)
 
269
            ok, value = dia.run()
 
270
            if ok:
 
271
                self._view.modelfield.set_client(self._view.model, value,
 
272
                        force_change=True)
 
273
            dia.destroy()
 
274
        self.wid_text_focus_out_id = self.wid_text.connect_after('focus-out-event', self.sig_focus_out, True)
 
275
        self.display(self._view.model, self._view.modelfield)
 
276
        self.ok=True
 
277
 
 
278
    def sig_focus_out(self, widget, event=None, leave=False):
 
279
        res = self._view.modelfield.get_client(self._view.model)
 
280
        if self.wid_text.get_text() and not res:
 
281
            self.sig_find(widget, event, leave=True)
 
282
 
 
283
    def sig_activate(self, widget, event=None, leave=False):
 
284
        self.sig_find(widget, event, leave=True)
 
285
 
 
286
    def sig_new(self, *args):
 
287
        self.wid_text.disconnect(self.wid_text_focus_out_id)
 
288
        domain = self._view.modelfield.domain_get(self._view.model)
 
289
        context = self._view.modelfield.context_get(self._view.model)
 
290
        dia = dialog(self.attrs['relation'], attrs=self.attrs, window=self._window, domain=domain ,context=context)
 
291
        ok, value = dia.run()
 
292
        if ok:
 
293
            self._view.modelfield.set_client(self._view.model, value)
 
294
            self.display(self._view.model, self._view.modelfield)
 
295
        dia.destroy()
 
296
        self.wid_text_focus_out_id = self.wid_text.connect_after('focus-out-event', self.sig_focus_out, True)
 
297
 
 
298
    def sig_key_press(self, widget, event, *args):
 
299
        if event.keyval==gtk.keysyms.F1:
 
300
            self.sig_new(widget, event)
 
301
        elif event.keyval==gtk.keysyms.F2:
 
302
            self.sig_activate(widget, event)
 
303
        elif event.keyval==gtk.keysyms.F3:
 
304
            self.sig_edit(widget, event)
 
305
        elif event.keyval  == gtk.keysyms.Tab:
 
306
            if self._view.modelfield.get(self._view.model) or \
 
307
                    not self.wid_text.get_text():
 
308
                return False
 
309
            self.sig_activate(widget, event, leave=True)
 
310
            return True
 
311
        return False
 
312
 
 
313
    def sig_changed(self, *args):
 
314
        if self.ok:
 
315
            if self._view.modelfield.get(self._view.model):
 
316
                self._view.modelfield.set_client(self._view.model, False)
 
317
                self.display(self._view.model, self._view.modelfield)
 
318
        return False
 
319
 
 
320
    def set_value(self, model, model_field):
 
321
        pass # No update of the model, the model is updated in real time !
 
322
 
 
323
    def display(self, model, model_field):
 
324
        if not model_field:
 
325
            self.ok = False
 
326
            self.wid_text.set_text('')
 
327
            return False
 
328
        super(many2one, self).display(model, model_field)
 
329
        self.ok=False
 
330
        res = model_field.get_client(model)
 
331
        self.wid_text.set_text((res and str(res)) or '')
 
332
        self.but_open.set_sensitive(bool(res))
 
333
        self.ok=True
 
334
 
 
335
    def _menu_open(self, obj, event):
 
336
        if event.button == 3:
 
337
            value = self._view.modelfield.get(self._view.model)
 
338
            if not self._menu_loaded:
 
339
                resrelate = rpc.session.rpc_exec_auth('/object', 'execute', 'ir.values', 'get', 'action', 'client_action_relate', [(self.model_type, False)], False, rpc.session.context)
 
340
                resrelate = map(lambda x:x[2], resrelate)
 
341
                self._menu_entries.append((None, None, None))
 
342
                for x in resrelate:
 
343
                    x['string'] = x['name']
 
344
                    f = lambda action: lambda x: self.click_and_relate(action)
 
345
                    self._menu_entries.append(('... '+x['name'], f(x), 0))
 
346
            self._menu_loaded = True
 
347
 
 
348
            menu = gtk.Menu()
 
349
            for stock_id,callback,sensitivity in self._menu_entries:
 
350
                if stock_id:
 
351
                    item = gtk.ImageMenuItem(stock_id)
 
352
                    if callback:
 
353
                        item.connect("activate",callback)
 
354
                    item.set_sensitive(bool(sensitivity or value))
 
355
                else:
 
356
                    item=gtk.SeparatorMenuItem()
 
357
                item.show()
 
358
                menu.append(item)
 
359
            menu.popup(None,None,None,event.button,event.time)
 
360
            return True
 
361
        return False
 
362
 
 
363
    def click_and_relate(self, action):
 
364
        data={}
 
365
        context={}
 
366
        act=action.copy()
 
367
        id = self._view.modelfield.get(self._view.model)
 
368
        if not(id):
 
369
            common.message(_('You must select a record to use the relation !'))
 
370
            return False
 
371
        screen = Screen(self.attrs['relation'])
 
372
        screen.load([id])
 
373
        act['domain'] = screen.current_model.expr_eval(act['domain'], check_load=False)
 
374
        act['context'] = str(screen.current_model.expr_eval(act['context'], check_load=False))
 
375
        obj = service.LocalService('action.main')
 
376
        value = obj._exec_action(act, data, context)
 
377
        return value
 
378
 
 
379
    def click_and_action(self, type):
 
380
        id = self._view.modelfield.get(self._view.model)
 
381
        obj = service.LocalService('action.main')
 
382
        res = obj.exec_keyword(type, {'model':self.model_type, 'id': id or False, 'ids':[id], 'report_type': 'pdf'})
 
383
        return True
 
384
 
 
385
 
 
386
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
 
387