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

« back to all changes in this revision

Viewing changes to bin/common/common.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 gtk
 
24
from gtk import glade
 
25
import gobject
 
26
 
 
27
import gettext
 
28
 
 
29
import os
 
30
import sys
 
31
import common
 
32
import logging
 
33
from options import options
 
34
import service
 
35
 
 
36
import ConfigParser
 
37
 
 
38
import threading
 
39
import time
 
40
 
 
41
#
 
42
# Upgrade this number to force the client to ask the survey
 
43
#
 
44
SURVEY_VERSION = '3'
 
45
 
 
46
def _search_file(file, dir='path.share'):
 
47
    tests = [
 
48
        lambda x: os.path.join(os.getcwd(), os.path.dirname(sys.argv[0]), x),
 
49
        lambda x: os.path.join(os.getcwd(), os.path.dirname(sys.argv[0]), 'pixmaps', x),
 
50
        lambda x: os.path.join(options.options[dir],x),
 
51
    ]
 
52
    for func in tests:
 
53
        x = func(file)
 
54
        if os.path.exists(x):
 
55
            return x
 
56
    return False
 
57
 
 
58
terp_path = _search_file
 
59
terp_path_pixmaps = lambda x: _search_file(x, 'path.pixmaps')
 
60
 
 
61
OPENERP_ICON = gtk.gdk.pixbuf_new_from_file(
 
62
            terp_path_pixmaps('openerp-icon.png'))
 
63
 
 
64
def selection(title, values, alwaysask=False, parent=None):
 
65
    if not values or len(values)==0:
 
66
        return None
 
67
    elif len(values)==1 and (not alwaysask):
 
68
        key = values.keys()[0]
 
69
        return (key, values[key])
 
70
 
 
71
    xml = glade.XML(terp_path("openerp.glade"), "win_selection", gettext.textdomain())
 
72
    win = xml.get_widget('win_selection')
 
73
    if not parent:
 
74
        parent = service.LocalService('gui.main').window
 
75
    win.set_icon(OPENERP_ICON)
 
76
    win.set_transient_for(parent)
 
77
 
 
78
    label = xml.get_widget('win_sel_title')
 
79
    if title:
 
80
        label.set_text(title)
 
81
 
 
82
    list = xml.get_widget('win_sel_tree')
 
83
    list.get_selection().set_mode('single')
 
84
    cell = gtk.CellRendererText()
 
85
    column = gtk.TreeViewColumn("Widget", cell, text=0)
 
86
    list.append_column(column)
 
87
    list.set_search_column(0)
 
88
    model = gtk.ListStore(gobject.TYPE_STRING)
 
89
    keys = values.keys()
 
90
    keys.sort()
 
91
    for val in keys:
 
92
        model.append([val])
 
93
 
 
94
    list.set_model(model)
 
95
    list.connect('row-activated', lambda x,y,z: win.response(gtk.RESPONSE_OK) or True)
 
96
 
 
97
    ok = False
 
98
    while not ok:
 
99
        response = win.run()
 
100
        ok = True
 
101
        res = None
 
102
        if response == gtk.RESPONSE_OK:
 
103
            sel = list.get_selection().get_selected()
 
104
            if sel:
 
105
                (model, iter) = sel
 
106
                if iter:
 
107
                    res = model.get_value(iter, 0)
 
108
                    res = (res, values[res])
 
109
                else:
 
110
                    ok = False
 
111
            else:
 
112
                ok = False
 
113
        else:
 
114
            res = None
 
115
    parent.present()
 
116
    win.destroy()
 
117
    return res
 
118
 
 
119
class upload_data_thread(threading.Thread):
 
120
    def __init__(self, email, data, type, supportid):
 
121
        self.args = [('email',email),('type',type),('supportid',supportid),('data',data)]
 
122
        super(upload_data_thread,self).__init__()
 
123
    def run(self):
 
124
        try:
 
125
            import urllib
 
126
            args = urllib.urlencode(self.args)
 
127
            fp = urllib.urlopen('http://www.openerp.com/scripts/survey.php', args)
 
128
            fp.read()
 
129
            fp.close()
 
130
        except:
 
131
            pass
 
132
 
 
133
def upload_data(email, data, type='SURVEY', supportid=''):
 
134
    a = upload_data_thread(email, data, type, supportid)
 
135
    a.start()
 
136
    return True
 
137
 
 
138
def terp_survey():
 
139
    if options.options['survey.position']==SURVEY_VERSION:
 
140
        return False
 
141
    import pickle
 
142
    widnames = ('country','role','industry','employee','hear','system','opensource')
 
143
    winglade = glade.XML(common.terp_path("openerp.glade"), "dia_survey", gettext.textdomain())
 
144
    win = winglade.get_widget('dia_survey')
 
145
    parent = service.LocalService('gui.main').window
 
146
    win.set_transient_for(parent)
 
147
    win.set_icon(OPENERP_ICON)
 
148
    for widname in widnames:
 
149
        wid = winglade.get_widget('combo_'+widname)
 
150
        wid.child.set_text('(choose one)')
 
151
        wid.child.set_editable(False)
 
152
    res = win.run()
 
153
    if res==gtk.RESPONSE_OK:
 
154
        email =  winglade.get_widget('entry_email').get_text()
 
155
        company =  winglade.get_widget('entry_company').get_text()
 
156
        result = "\ncompany: "+str(company)
 
157
        for widname in widnames:
 
158
            wid = winglade.get_widget('combo_'+widname)
 
159
            result += "\n"+widname+": "+wid.child.get_text()
 
160
        result += "\nplan_use: "+str(winglade.get_widget('check_use').get_active())
 
161
        result += "\nplan_sell: "+str(winglade.get_widget('check_sell').get_active())
 
162
 
 
163
        buffer = winglade.get_widget('textview_comment').get_buffer()
 
164
        iter_start = buffer.get_start_iter()
 
165
        iter_end = buffer.get_end_iter()
 
166
        result += "\nnote: "+buffer.get_text(iter_start,iter_end,False)
 
167
        parent.present()
 
168
        win.destroy()
 
169
        upload_data(email, result, type='SURVEY '+str(SURVEY_VERSION))
 
170
        options.options['survey.position']=SURVEY_VERSION
 
171
        options.save()
 
172
        common.message(_('Thank you for the feedback !\nYour comments have been sent to OpenERP.\nYou should now start by creating a new database or\nconnecting to an existing server through the "File" menu.'))
 
173
    else:
 
174
        parent.present()
 
175
        win.destroy()
 
176
        common.message(_('Thank you for testing OpenERP !\nYou should now start by creating a new database or\nconnecting to an existing server through the "File" menu.'))
 
177
    return True
 
178
 
 
179
 
 
180
def file_selection(title, filename='', parent=None,
 
181
        action=gtk.FILE_CHOOSER_ACTION_OPEN, preview=True, multi=False, filters=None):
 
182
    if action == gtk.FILE_CHOOSER_ACTION_OPEN:
 
183
        buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
 
184
            gtk.STOCK_OPEN,gtk.RESPONSE_OK)
 
185
    else:
 
186
        buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
 
187
            gtk.STOCK_SAVE, gtk.RESPONSE_OK)
 
188
    win = gtk.FileChooserDialog(title, None, action, buttons)
 
189
    if not parent:
 
190
        parent = service.LocalService('gui.main').window
 
191
    win.set_transient_for(parent)
 
192
    win.set_icon(OPENERP_ICON)
 
193
    win.set_current_folder(options.options['client.default_path'])
 
194
    win.set_select_multiple(multi)
 
195
    win.set_default_response(gtk.RESPONSE_OK)
 
196
    if filters is not None:
 
197
        for filter in filters:
 
198
            win.add_filter(filter)
 
199
    if filename:
 
200
        win.set_current_name(filename)
 
201
 
 
202
    def update_preview_cb(win, img):
 
203
        filename = win.get_preview_filename()
 
204
        try:
 
205
            pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(filename, 128, 128)
 
206
            img.set_from_pixbuf(pixbuf)
 
207
            have_preview = True
 
208
        except:
 
209
            have_preview = False
 
210
        win.set_preview_widget_active(have_preview)
 
211
        return
 
212
 
 
213
    if preview:
 
214
        img_preview = gtk.Image()
 
215
        win.set_preview_widget(img_preview)
 
216
        win.connect('update-preview', update_preview_cb, img_preview)
 
217
 
 
218
    button = win.run()
 
219
    if button!=gtk.RESPONSE_OK:
 
220
        win.destroy()
 
221
        return False
 
222
    if not multi:
 
223
        filepath = win.get_filename()
 
224
        if filepath:
 
225
            filepath = filepath.decode('utf-8')
 
226
            try:
 
227
                options.options['client.default_path'] = os.path.dirname(filepath)
 
228
            except:
 
229
                pass
 
230
        parent.present()
 
231
        win.destroy()
 
232
        return filepath
 
233
    else:
 
234
        filenames = win.get_filenames()
 
235
        if filenames:
 
236
            filenames = [x.decode('utf-8') for x in filenames]
 
237
            try:
 
238
                options.options['client.default_path'] = os.path.dirname(filenames[0])
 
239
            except:
 
240
                pass
 
241
        parent.present()
 
242
        win.destroy()
 
243
        return filenames
 
244
 
 
245
def support(*args):
 
246
    import pickle
 
247
    wid_list = ['email_entry','id_entry','name_entry','phone_entry','company_entry','error_details','explanation_textview','remark_textview']
 
248
    required_wid = ['email_entry', 'name_entry', 'company_name', 'id_entry']
 
249
    support_id = options['support.support_id']
 
250
    recipient = options['support.recipient']
 
251
 
 
252
    sur = glade.XML(terp_path("openerp.glade"), "dia_support",gettext.textdomain())
 
253
    win = sur.get_widget('dia_support')
 
254
    parent = service.LocalService('gui.main').window
 
255
    win.set_transient_for(parent)
 
256
    win.set_icon(OPENERP_ICON)
 
257
    win.show_all()
 
258
    sur.get_widget('id_entry1').set_text(support_id)
 
259
 
 
260
    response = win.run()
 
261
    if response == gtk.RESPONSE_OK:
 
262
        fromaddr = sur.get_widget('email_entry1').get_text()
 
263
        id_contract = sur.get_widget('id_entry1').get_text()
 
264
        name =  sur.get_widget('name_entry1').get_text()
 
265
        phone =  sur.get_widget('phone_entry1').get_text()
 
266
        company =  sur.get_widget('company_entry1').get_text()
 
267
 
 
268
        urgency = sur.get_widget('urgency_combo1').get_active_text()
 
269
 
 
270
        buffer = sur.get_widget('explanation_textview1').get_buffer()
 
271
        explanation = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter())
 
272
 
 
273
        buffer = sur.get_widget('remark_textview').get_buffer()
 
274
        remarks = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter())
 
275
 
 
276
        content = name +"(%s, %s, %s)"%(id_contract, company, phone) +" has reported the following bug:\n"+ explanation + "\nremarks:\n" + remarks
 
277
 
 
278
        if upload_data(fromaddr, content, 'support', id_contract):
 
279
            common.message(_('Support request sent !'))
 
280
 
 
281
    parent.present()
 
282
    win.destroy()
 
283
    return True
 
284
 
 
285
def error(title, message, details='', parent=None):
 
286
    log = logging.getLogger('common.message')
 
287
    log.error('MSG %s: %s' % (str(message),details))
 
288
 
 
289
    wid_list = ['email_entry','id_entry','name_entry','phone_entry','company_entry','error_details','explanation_textview','remarks_textview']
 
290
    required_wid = ['email_entry', 'name_entry', 'company_name', 'id_entry']
 
291
    colors = {'invalid':'#ffdddd', 'readonly':'grey', 'required':'#ddddff', 'normal':'white'}
 
292
 
 
293
    support_id = options['support.support_id']
 
294
    recipient = options['support.recipient']
 
295
 
 
296
    sur = glade.XML(terp_path("openerp.glade"), "win_error",gettext.textdomain())
 
297
    win = sur.get_widget('win_error')
 
298
    if not parent:
 
299
        parent=service.LocalService('gui.main').window
 
300
    win.set_transient_for(parent)
 
301
    win.set_icon(OPENERP_ICON)
 
302
    sur.get_widget('error_title').set_text(str(title))
 
303
    sur.get_widget('error_info').set_text(str(message))
 
304
    buf = gtk.TextBuffer()
 
305
    buf.set_text(unicode(details,'latin1').encode('utf-8'))
 
306
    sur.get_widget('error_details').set_buffer(buf)
 
307
 
 
308
    sur.get_widget('id_entry').set_text(support_id)
 
309
 
 
310
    def send(widget):
 
311
        import pickle
 
312
 
 
313
        fromaddr = sur.get_widget('email_entry').get_text()
 
314
        id_contract = sur.get_widget('id_entry').get_text()
 
315
        name =  sur.get_widget('name_entry').get_text()
 
316
        phone =  sur.get_widget('phone_entry').get_text()
 
317
        company =  sur.get_widget('company_entry').get_text()
 
318
 
 
319
        urgency = sur.get_widget('urgency_combo').get_active_text()
 
320
 
 
321
        buffer = sur.get_widget('error_details').get_buffer()
 
322
        traceback = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter())
 
323
 
 
324
        buffer = sur.get_widget('explanation_textview').get_buffer()
 
325
        explanation = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter())
 
326
 
 
327
        buffer = sur.get_widget('remarks_textview').get_buffer()
 
328
        remarks = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter())
 
329
 
 
330
        content = "(%s, %s, %s)"%(id_contract, company, phone) +" has reported the following bug:\n"+ explanation + "\nremarks: " + remarks + "\nThe traceback is:\n" + traceback
 
331
 
 
332
        if upload_data(fromaddr, content, 'error', id_contract):
 
333
            common.message(_('Support request sent !'))
 
334
        return
 
335
 
 
336
    sur.signal_connect('on_button_send_clicked', send)
 
337
    sur.signal_connect('on_closebutton_clicked', lambda x : win.destroy())
 
338
 
 
339
    response = win.run()
 
340
    parent.present()
 
341
    win.destroy()
 
342
    return True
 
343
 
 
344
def message(msg, type=gtk.MESSAGE_INFO, parent=None):
 
345
    if not parent:
 
346
        parent=service.LocalService('gui.main').window
 
347
    dialog = gtk.MessageDialog(parent,
 
348
      gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
 
349
      type, gtk.BUTTONS_OK,
 
350
      msg)
 
351
    dialog.set_icon(OPENERP_ICON)
 
352
    dialog.run()
 
353
    parent.present()
 
354
    dialog.destroy()
 
355
    return True
 
356
 
 
357
def to_xml(s):
 
358
    return s.replace('&','&amp;').replace('<','&lt;').replace('>','&gt;')
 
359
 
 
360
def message_box(title, msg, parent=None):
 
361
    dia = glade.XML(terp_path("openerp.glade"), "dia_message_box",gettext.textdomain())
 
362
    win = dia.get_widget('dia_message_box')
 
363
    l = dia.get_widget('msg_title')
 
364
    l.set_text(title)
 
365
 
 
366
    buffer = dia.get_widget('msg_tv').get_buffer()
 
367
    iter_start = buffer.get_start_iter()
 
368
    buffer.insert(iter_start, msg)
 
369
 
 
370
    if not parent:
 
371
        parent=service.LocalService('gui.main').window
 
372
    win.set_transient_for(parent)
 
373
    win.set_icon(OPENERP_ICON)
 
374
 
 
375
    response = win.run()
 
376
    parent.present()
 
377
    win.destroy()
 
378
    return True
 
379
 
 
380
 
 
381
def warning(msg, title='', parent=None):
 
382
    if not parent:
 
383
        parent=service.LocalService('gui.main').window
 
384
    dialog = gtk.MessageDialog(parent, gtk.DIALOG_DESTROY_WITH_PARENT,
 
385
            gtk.MESSAGE_WARNING, gtk.BUTTONS_OK)
 
386
    dialog.set_icon(OPENERP_ICON)
 
387
    dialog.set_markup('<b>%s</b>\n\n%s' % (to_xml(title),to_xml(msg)))
 
388
    dialog.show_all()
 
389
    dialog.run()
 
390
    parent.present()
 
391
    dialog.destroy()
 
392
    return True
 
393
 
 
394
def sur(msg, parent=None):
 
395
    if not parent:
 
396
        parent=service.LocalService('gui.main').window
 
397
    sur = glade.XML(terp_path("openerp.glade"), "win_sur",gettext.textdomain())
 
398
    win = sur.get_widget('win_sur')
 
399
    win.set_transient_for(parent)
 
400
    win.show_all()
 
401
    l = sur.get_widget('lab_question')
 
402
    l.set_text(msg)
 
403
 
 
404
    if not parent:
 
405
        parent=service.LocalService('gui.main').window
 
406
    win.set_transient_for(parent)
 
407
    win.set_icon(OPENERP_ICON)
 
408
 
 
409
    response = win.run()
 
410
    parent.present()
 
411
    win.destroy()
 
412
    return response == gtk.RESPONSE_OK
 
413
 
 
414
def sur_3b(msg, parent=None):
 
415
    sur = glade.XML(terp_path("openerp.glade"), "win_quest_3b",gettext.textdomain())
 
416
    win = sur.get_widget('win_quest_3b')
 
417
    l = sur.get_widget('label')
 
418
    l.set_text(msg)
 
419
 
 
420
    if not parent:
 
421
        parent=service.LocalService('gui.main').window
 
422
    win.set_transient_for(parent)
 
423
    win.set_icon(OPENERP_ICON)
 
424
 
 
425
    response = win.run()
 
426
    parent.present()
 
427
    win.destroy()
 
428
    if response == gtk.RESPONSE_YES:
 
429
        return 'ok'
 
430
    elif response == gtk.RESPONSE_NO:
 
431
        return 'ko'
 
432
    elif response == gtk.RESPONSE_CANCEL:
 
433
        return 'cancel'
 
434
    else:
 
435
        return 'cancel'
 
436
 
 
437
def theme_set():
 
438
    theme = options['client.theme']
 
439
    if theme and (theme <> 'none'):
 
440
        fname = os.path.join("themes", theme, "gtkrc")
 
441
        if not os.path.isfile(fname):
 
442
            common.warning('File not found: '+fname+'\nSet theme to none in ~/.openerprc', 'Error setting theme')
 
443
            return False
 
444
        gtk.rc_parse("themes/"+theme+"/gtkrc")
 
445
    return True
 
446
 
 
447
def ask(question, parent=None):
 
448
    dia = glade.XML(terp_path('openerp.glade'), 'win_quest', gettext.textdomain())
 
449
    win = dia.get_widget('win_quest')
 
450
    label = dia.get_widget('label1')
 
451
    label.set_text(question)
 
452
    entry = dia.get_widget('entry')
 
453
 
 
454
    if not parent:
 
455
        parent=service.LocalService('gui.main').window
 
456
    win.set_transient_for(parent)
 
457
    win.set_icon(OPENERP_ICON)
 
458
 
 
459
    response = win.run()
 
460
    parent.present()
 
461
    win.destroy()
 
462
    if response == gtk.RESPONSE_CANCEL:
 
463
        return None
 
464
    else:
 
465
        return entry.get_text()
 
466
 
 
467
def concurrency(resource, id, context, parent=None):
 
468
    dia = glade.XML(common.terp_path("openerp.glade"),'dialog_concurrency_exception',gettext.textdomain())
 
469
    win = dia.get_widget('dialog_concurrency_exception')
 
470
 
 
471
    if not parent:
 
472
        parent=service.LocalService('gui.main').window
 
473
    win.set_transient_for(parent)
 
474
    win.set_icon(OPENERP_ICON)
 
475
 
 
476
    res= win.run()
 
477
    parent.present()
 
478
    win.destroy()
 
479
 
 
480
    if res == gtk.RESPONSE_OK:
 
481
        return True
 
482
    if res == gtk.RESPONSE_APPLY:
 
483
        obj = service.LocalService('gui.window')
 
484
        obj.create(False, resource, id, [], 'form', None, context,'form,tree')
 
485
    return False
 
486
 
 
487
def open_file(value, parent):
 
488
    filetype = {}
 
489
    if options['client.filetype']:
 
490
        if isinstance(options['client.filetype'], str):
 
491
            filetype = eval(options['client.filetype'])
 
492
        else:
 
493
            filetype = options['client.filetype']
 
494
    root, ext = os.path.splitext(value)
 
495
    cmd = False
 
496
    if ext[1:] in filetype:
 
497
        cmd = filetype[ext[1:]] % (value)
 
498
    if not cmd:
 
499
        cmd = file_selection(_('Open with...'),
 
500
                parent=parent)
 
501
        if cmd:
 
502
            cmd = cmd + ' %s'
 
503
            filetype[ext[1:]] = cmd
 
504
            options['client.filetype'] = filetype
 
505
            options.save()
 
506
            cmd = cmd % (value)
 
507
    if cmd:
 
508
        pid = os.fork()
 
509
        if not pid:
 
510
            pid = os.fork()
 
511
            if not pid:
 
512
                prog, args = cmd.split(' ', 1)
 
513
                args = [os.path.basename(prog)] + args.split(' ')
 
514
                try:
 
515
                    os.execvp(prog, args)
 
516
                except:
 
517
                    pass
 
518
            time.sleep(0.1)
 
519
            sys.exit(0)
 
520
        os.waitpid(pid, 0)
 
521
 
 
522
 
 
523
# Color set
 
524
 
 
525
colors = {
 
526
    'invalid':'#ff6969',
 
527
    'readonly':'#eeebe7',
 
528
    'required':'#d2d2ff',
 
529
    'normal':'white'
 
530
}
 
531
 
 
532
 
 
533
 
 
534
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
 
535