1 # -*- encoding: utf-8 -*-
2 ##############################################################################
4 # Copyright (c) 2004-2008 TINY SPRL. (http://tiny.be) All Rights Reserved.
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
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 ##############################################################################
41 from options
import options
50 # Upgrade this number to force the client to ask the survey
54 def _search_file(file, dir='path.share'):
56 lambda x
: os
.path
.join(os
.getcwd(), os
.path
.dirname(sys
.argv
[0]), x
),
57 lambda x
: os
.path
.join(os
.getcwd(), os
.path
.dirname(sys
.argv
[0]), 'pixmaps', x
),
58 lambda x
: os
.path
.join(options
.options
[dir],x
),
66 terp_path
= _search_file
67 terp_path_pixmaps
= lambda x
: _search_file(x
, 'path.pixmaps')
69 TINYERP_ICON
= gtk
.gdk
.pixbuf_new_from_file(
70 terp_path_pixmaps('tinyerp-icon-32x32.png'))
72 def selection(title
, values
, alwaysask
=False, parent
=None):
73 if not values
or len(values
)==0:
75 elif len(values
)==1 and (not alwaysask
):
76 key
= values
.keys()[0]
77 return (key
, values
[key
])
79 xml
= glade
.XML(terp_path("terp.glade"), "win_selection", gettext
.textdomain())
80 win
= xml
.get_widget('win_selection')
82 parent
= service
.LocalService('gui.main').window
83 win
.set_icon(TINYERP_ICON
)
84 win
.set_transient_for(parent
)
86 label
= xml
.get_widget('win_sel_title')
90 list = xml
.get_widget('win_sel_tree')
91 list.get_selection().set_mode('single')
92 cell
= gtk
.CellRendererText()
93 column
= gtk
.TreeViewColumn("Widget", cell
, text
=0)
94 list.append_column(column
)
95 list.set_search_column(0)
96 model
= gtk
.ListStore(gobject
.TYPE_STRING
)
102 list.set_model(model
)
103 list.connect('row-activated', lambda x
,y
,z
: win
.response(gtk
.RESPONSE_OK
) or True)
110 if response
== gtk
.RESPONSE_OK
:
111 sel
= list.get_selection().get_selected()
115 res
= model
.get_value(iter, 0)
116 res
= (res
, values
[res
])
127 class upload_data_thread(threading
.Thread
):
128 def __init__(self
, email
, data
, type, supportid
):
129 self
.args
= [('email',email
),('type',type),('supportid',supportid
),('data',data
)]
130 super(upload_data_thread
,self
).__init
__()
134 args
= urllib
.urlencode(self
.args
)
135 fp
= urllib
.urlopen('http://www.tinyerp.com/scripts/survey.php', args
)
141 def upload_data(email
, data
, type='SURVEY', supportid
=''):
142 a
= upload_data_thread(email
, data
, type, supportid
)
147 if options
.options
['survey.position']==SURVEY_VERSION
:
150 widnames
= ('country','role','industry','employee','hear','system','opensource')
151 winglade
= glade
.XML(common
.terp_path("terp.glade"), "dia_survey", gettext
.textdomain())
152 win
= winglade
.get_widget('dia_survey')
153 parent
= service
.LocalService('gui.main').window
154 win
.set_transient_for(parent
)
155 win
.set_icon(TINYERP_ICON
)
156 for widname
in widnames
:
157 wid
= winglade
.get_widget('combo_'+widname
)
158 wid
.child
.set_text('(choose one)')
159 wid
.child
.set_editable(False)
161 if res
==gtk
.RESPONSE_OK
:
162 email
= winglade
.get_widget('entry_email').get_text()
163 company
= winglade
.get_widget('entry_company').get_text()
164 result
= "\ncompany: "+str(company
)
165 for widname
in widnames
:
166 wid
= winglade
.get_widget('combo_'+widname
)
167 result
+= "\n"+widname
+": "+wid
.child
.get_text()
168 result
+= "\nplan_use: "+str(winglade
.get_widget('check_use').get_active())
169 result
+= "\nplan_sell: "+str(winglade
.get_widget('check_sell').get_active())
171 buffer = winglade
.get_widget('textview_comment').get_buffer()
172 iter_start
= buffer.get_start_iter()
173 iter_end
= buffer.get_end_iter()
174 result
+= "\nnote: "+buffer.get_text(iter_start
,iter_end
,False)
177 upload_data(email
, result
, type='SURVEY '+str(SURVEY_VERSION
))
178 options
.options
['survey.position']=SURVEY_VERSION
180 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.'))
184 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.'))
188 def file_selection(title
, filename
='', parent
=None,
189 action
=gtk
.FILE_CHOOSER_ACTION_OPEN
, preview
=True, multi
=False, filters
=None):
190 if action
== gtk
.FILE_CHOOSER_ACTION_OPEN
:
191 buttons
=(gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
,
192 gtk
.STOCK_OPEN
,gtk
.RESPONSE_OK
)
194 buttons
=(gtk
.STOCK_CANCEL
, gtk
.RESPONSE_CANCEL
,
195 gtk
.STOCK_SAVE
, gtk
.RESPONSE_OK
)
196 win
= gtk
.FileChooserDialog(title
, None, action
, buttons
)
198 parent
= service
.LocalService('gui.main').window
199 win
.set_transient_for(parent
)
200 win
.set_icon(TINYERP_ICON
)
201 win
.set_current_folder(options
.options
['client.default_path'])
202 win
.set_select_multiple(multi
)
203 win
.set_default_response(gtk
.RESPONSE_OK
)
204 if filters
is not None:
205 for filter in filters
:
206 win
.add_filter(filter)
208 win
.set_current_name(filename
)
210 def update_preview_cb(win
, img
):
211 filename
= win
.get_preview_filename()
213 pixbuf
= gtk
.gdk
.pixbuf_new_from_file_at_size(filename
, 128, 128)
214 img
.set_from_pixbuf(pixbuf
)
218 win
.set_preview_widget_active(have_preview
)
222 img_preview
= gtk
.Image()
223 win
.set_preview_widget(img_preview
)
224 win
.connect('update-preview', update_preview_cb
, img_preview
)
227 if button
!=gtk
.RESPONSE_OK
:
231 filepath
= win
.get_filename()
233 filepath
= filepath
.decode('utf-8')
235 options
.options
['client.default_path'] = os
.path
.dirname(filepath
)
242 filenames
= win
.get_filenames()
244 filenames
= [x
.decode('utf-8') for x
in filenames
]
246 options
.options
['client.default_path'] = os
.path
.dirname(filenames
[0])
255 wid_list
= ['email_entry','id_entry','name_entry','phone_entry','company_entry','error_details','explanation_textview','remark_textview']
256 required_wid
= ['email_entry', 'name_entry', 'company_name', 'id_entry']
257 support_id
= options
['support.support_id']
258 recipient
= options
['support.recipient']
260 sur
= glade
.XML(terp_path("terp.glade"), "dia_support",gettext
.textdomain())
261 win
= sur
.get_widget('dia_support')
262 parent
= service
.LocalService('gui.main').window
263 win
.set_transient_for(parent
)
264 win
.set_icon(TINYERP_ICON
)
266 sur
.get_widget('id_entry').set_text(support_id
)
269 if response
== gtk
.RESPONSE_OK
:
270 fromaddr
= sur
.get_widget('email_entry').get_text()
271 id_contract
= sur
.get_widget('id_entry').get_text()
272 name
= sur
.get_widget('name_entry').get_text()
273 phone
= sur
.get_widget('phone_entry').get_text()
274 company
= sur
.get_widget('company_entry').get_text()
276 urgency
= sur
.get_widget('urgency_combo').get_active_text()
278 buffer = sur
.get_widget('explanation_textview').get_buffer()
279 explanation
= buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter())
281 buffer = sur
.get_widget('remark_textview').get_buffer()
282 remarks
= buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter())
284 content
= name
+"(%s, %s, %s)"%(id_contract
, company
, phone
) +" has reported the following bug:\n"+ explanation
+ "\nremarks:\n" + remarks
286 if upload_data(fromaddr
, content
, 'support', id_contract
):
287 common
.message(_('Support request sent !'))
293 def error(title
, message
, details
='', parent
=None):
294 log
= logging
.getLogger('common.message')
295 log
.error('MSG %s: %s' % (str(message
),details
))
297 wid_list
= ['email_entry','id_entry','name_entry','phone_entry','company_entry','error_details','explanation_textview','remarks_textview']
298 required_wid
= ['email_entry', 'name_entry', 'company_name', 'id_entry']
299 colors
= {'invalid':'#ffdddd', 'readonly':'grey', 'required':'#ddddff', 'normal':'white'}
301 support_id
= options
['support.support_id']
302 recipient
= options
['support.recipient']
304 sur
= glade
.XML(terp_path("terp.glade"), "win_error",gettext
.textdomain())
305 win
= sur
.get_widget('win_error')
307 parent
=service
.LocalService('gui.main').window
308 win
.set_transient_for(parent
)
309 win
.set_icon(TINYERP_ICON
)
310 sur
.get_widget('error_title').set_text(str(title
))
311 sur
.get_widget('error_info').set_text(str(message
))
312 buf
= gtk
.TextBuffer()
313 buf
.set_text(unicode(details
,'latin1').encode('utf-8'))
314 sur
.get_widget('error_details').set_buffer(buf
)
316 sur
.get_widget('id_entry').set_text(support_id
)
321 fromaddr
= sur
.get_widget('email_entry').get_text()
322 id_contract
= sur
.get_widget('id_entry').get_text()
323 name
= sur
.get_widget('name_entry').get_text()
324 phone
= sur
.get_widget('phone_entry').get_text()
325 company
= sur
.get_widget('company_entry').get_text()
327 urgency
= sur
.get_widget('urgency_combo').get_active_text()
329 buffer = sur
.get_widget('error_details').get_buffer()
330 traceback
= buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter())
332 buffer = sur
.get_widget('explanation_textview').get_buffer()
333 explanation
= buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter())
335 buffer = sur
.get_widget('remarks_textview').get_buffer()
336 remarks
= buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter())
338 content
= "(%s, %s, %s)"%(id_contract
, company
, phone
) +" has reported the following bug:\n"+ explanation
+ "\nremarks: " + remarks
+ "\nThe traceback is:\n" + traceback
340 if upload_data(fromaddr
, content
, 'error', id_contract
):
341 common
.message(_('Support request sent !'))
344 sur
.signal_connect('on_button_send_clicked', send
)
345 sur
.signal_connect('on_closebutton_clicked', lambda x
: win
.destroy())
352 def message(msg
, type=gtk
.MESSAGE_INFO
, parent
=None):
354 parent
=service
.LocalService('gui.main').window
355 dialog
= gtk
.MessageDialog(parent
,
356 gtk
.DIALOG_MODAL | gtk
.DIALOG_DESTROY_WITH_PARENT
,
357 type, gtk
.BUTTONS_OK
,
359 dialog
.set_icon(TINYERP_ICON
)
366 return s
.replace('&','&').replace('<','<').replace('>','>')
368 def message_box(title
, msg
, parent
=None):
369 dia
= glade
.XML(terp_path("terp.glade"), "dia_message_box",gettext
.textdomain())
370 win
= dia
.get_widget('dia_message_box')
371 l
= dia
.get_widget('msg_title')
374 buffer = dia
.get_widget('msg_tv').get_buffer()
375 iter_start
= buffer.get_start_iter()
376 buffer.insert(iter_start
, msg
)
379 parent
=service
.LocalService('gui.main').window
380 win
.set_transient_for(parent
)
381 win
.set_icon(TINYERP_ICON
)
389 def warning(msg
, title
='', parent
=None):
391 parent
=service
.LocalService('gui.main').window
392 dialog
= gtk
.MessageDialog(parent
, gtk
.DIALOG_DESTROY_WITH_PARENT
,
393 gtk
.MESSAGE_WARNING
, gtk
.BUTTONS_OK
)
394 dialog
.set_icon(TINYERP_ICON
)
395 dialog
.set_markup('<b>%s</b>\n\n%s' % (to_xml(title
),to_xml(msg
)))
402 def sur(msg
, parent
=None):
404 parent
=service
.LocalService('gui.main').window
405 sur
= glade
.XML(terp_path("terp.glade"), "win_sur",gettext
.textdomain())
406 win
= sur
.get_widget('win_sur')
407 win
.set_transient_for(parent
)
409 l
= sur
.get_widget('lab_question')
413 parent
=service
.LocalService('gui.main').window
414 win
.set_transient_for(parent
)
415 win
.set_icon(TINYERP_ICON
)
420 return response
== gtk
.RESPONSE_OK
422 def sur_3b(msg
, parent
=None):
423 sur
= glade
.XML(terp_path("terp.glade"), "win_quest_3b",gettext
.textdomain())
424 win
= sur
.get_widget('win_quest_3b')
425 l
= sur
.get_widget('label')
429 parent
=service
.LocalService('gui.main').window
430 win
.set_transient_for(parent
)
431 win
.set_icon(TINYERP_ICON
)
436 if response
== gtk
.RESPONSE_YES
:
438 elif response
== gtk
.RESPONSE_NO
:
440 elif response
== gtk
.RESPONSE_CANCEL
:
446 theme
= options
['client.theme']
447 if theme
and (theme
<> 'none'):
448 fname
= os
.path
.join("themes", theme
, "gtkrc")
449 if not os
.path
.isfile(fname
):
450 common
.warning('File not found: '+fname
+'\nSet theme to none in ~/.terprc', 'Error setting theme')
452 gtk
.rc_parse("themes/"+theme
+"/gtkrc")
455 def ask(question
, parent
=None):
456 dia
= glade
.XML(terp_path('terp.glade'), 'win_quest', gettext
.textdomain())
457 win
= dia
.get_widget('win_quest')
458 label
= dia
.get_widget('label1')
459 label
.set_text(question
)
460 entry
= dia
.get_widget('entry')
463 parent
=service
.LocalService('gui.main').window
464 win
.set_transient_for(parent
)
465 win
.set_icon(TINYERP_ICON
)
470 if response
== gtk
.RESPONSE_CANCEL
:
473 return entry
.get_text()
475 def concurrency(resource
, id, context
, parent
=None):
476 dia
= glade
.XML(common
.terp_path("terp.glade"),'dialog_concurrency_exception',gettext
.textdomain())
477 win
= dia
.get_widget('dialog_concurrency_exception')
480 parent
=service
.LocalService('gui.main').window
481 win
.set_transient_for(parent
)
482 win
.set_icon(TINYERP_ICON
)
488 if res
== gtk
.RESPONSE_OK
:
490 if res
== gtk
.RESPONSE_APPLY
:
491 obj
= service
.LocalService('gui.window')
492 obj
.create(False, resource
, id, [], 'form', None, context
,'form,tree')
495 def open_file(value
, parent
):
497 if options
['client.filetype']:
498 if isinstance(options
['client.filetype'], str):
499 filetype
= eval(options
['client.filetype'])
501 filetype
= options
['client.filetype']
502 root
, ext
= os
.path
.splitext(value
)
504 if ext
[1:] in filetype
:
505 cmd
= filetype
[ext
[1:]] % (value
)
507 cmd
= file_selection(_('Open with...'),
511 filetype
[ext
[1:]] = cmd
512 options
['client.filetype'] = filetype
520 prog
, args
= cmd
.split(' ', 1)
521 args
= [os
.path
.basename(prog
)] + args
.split(' ')
523 os
.execvp(prog
, args
)
535 'readonly':'#eeebe7',
536 'required':'#d2d2ff',
542 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: