Files
tryton/tryton/wizard/main.py
T

295 lines
10 KiB
Python

#This file is part of Tryton. The COPYRIGHT file at the top level of this repository contains the full copyright notices and license terms.
import gtk
import gettext
import tryton.rpc as rpc
import tryton.common as common
import thread, time
from tryton.gui.window.view_form.screen import Screen
import os
import pango
_ = gettext.gettext
class Dialog(object):
"Dialog for wizard"
def __init__(self, arch, fields, state, obj_name, parent,
context=None):
self.parent = parent
self.states = []
default = -1
self.dia = gtk.Dialog(_('Wizard'), parent,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
if hasattr(self.dia, 'set_deletable') and os.name != 'nt':
self.dia.set_deletable(False)
self.accel_group = gtk.AccelGroup()
self.dia.add_accel_group(self.accel_group)
for i in state:
but = gtk.Button(i[1])
but.show()
if len(i) >= 3:
icon = gtk.Image()
icon.set_from_stock(i[2], gtk.ICON_SIZE_BUTTON)
but.set_image(icon)
self.dia.add_action_widget(but, len(self.states))
if len(i) >= 4 and i[3]:
if default < 0:
default = len(self.states)
but.set_flags(gtk.CAN_DEFAULT)
but.add_accelerator('clicked', self.accel_group,
gtk.keysyms.Return, gtk.gdk.CONTROL_MASK,
gtk.ACCEL_VISIBLE)
self.dia.set_default_response(default)
self.states.append(i[0])
val = {}
for i in fields:
if 'value' in fields[i]:
val[i] = fields[i]['value']
self.screen = Screen(obj_name, self.dia, view_type=[], context=context)
self.screen.add_view_custom(arch, fields, display=True)
title = gtk.Label()
title.set_use_markup(True)
title.modify_font(pango.FontDescription("14"))
title.set_label('<b>' + self.screen.current_view.title + '</b>')
title.set_padding(20, 3)
title.set_alignment(0.0, 0.5)
title.show()
self.info_label = gtk.Label()
self.info_label.set_padding(3, 3)
self.info_label.set_alignment(1.0, 0.5)
self.eb_info = gtk.EventBox()
self.eb_info.add(self.info_label)
self.eb_info.connect('button-release-event',
lambda *a: self.message_info(''))
vbox = gtk.VBox()
vbox.pack_start(self.eb_info, expand=True, fill=True, padding=5)
vbox.show()
hbox = gtk.HBox()
hbox.pack_start(title, expand=True, fill=True)
hbox.pack_start(vbox, expand=False, fill=True, padding=20)
hbox.show()
frame = gtk.Frame()
frame.set_shadow_type(gtk.SHADOW_ETCHED_IN)
frame.add(hbox)
frame.show()
eb = gtk.EventBox()
eb.add(frame)
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#ffffff"))
eb.show()
self.dia.vbox.pack_start(eb, expand=False, fill=True, padding=3)
self.dia.vbox.pack_start(self.screen.widget, True, True)
width, height = self.screen.screen_container.size_get()
parent_width, parent_height = parent.get_size()
widget_width = min(parent_width - 20, width + 20)
widget_height = min(parent_height - 60, height + 25)
self.screen.widget.set_size_request(widget_width, widget_height)
self.screen.widget.show()
self.dia.set_title(self.screen.current_view.title)
self.dia.show()
self.screen.new(default=False)
self.screen.current_model.set(val)
self.screen.current_view.set_cursor()
def run(self, datas=None):
if datas is None:
datas = {}
while True:
res = self.dia.run()
self.screen.current_view.set_value()
if self.screen.current_model.validate() \
or (res<0) or (self.states[res]=='end'):
break
self.screen.display()
if res < len(self.states) and res >= 0:
datas.update(self.screen.get())
self.dia.hide()
self.parent.present()
return (self.states[res], datas)
else:
self.dia.hide()
self.parent.present()
return False
def destroy(self):
self.dia.destroy()
def message_info(self, message, color='red'):
if message:
self.info_label.set_label(message)
self.eb_info.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(
COLOR_SCHEMES.get(color, 'white')))
self.eb_info.show_all()
else:
self.info_label.set_label('')
self.eb_info.hide()
class Wizard(object):
@staticmethod
def execute(action, datas, parent, state='init', context=None):
from tryton.action import Action
if not 'form' in datas:
datas['form'] = {}
args = ('wizard', 'create', action)
try:
wiz_id = rpc.execute(*args)
except Exception, exception:
wiz_id = common.process_exception(exception, parent, *args)
if not wiz_id:
return
dia = None
while state != 'end':
ctx = context.copy()
ctx['active_id'] = datas.get('id')
ctx['active_ids'] = datas.get('ids')
wizardprogress = WizardProgress(wiz_id, state, datas,
parent, ctx)
res = wizardprogress.run()
if not res:
if dia:
res = {'type': 'form'}
else:
return
else:
if dia:
dia.destroy()
dia = None
if 'datas' in res:
datas['form'] = res['datas']
elif res['type'] == 'form':
datas['form'] = {}
if res['type'] == 'form':
if not dia:
dia = Dialog(res['arch'], res['fields'], res['state'],
res['object'], parent, context=ctx)
dia.screen.current_model.set(datas['form'])
res2 = dia.run(datas['form'])
if not res2:
break
(state, new_data) = res2
for data in new_data:
if new_data[data] is None:
del new_data[data]
datas['form'].update(new_data)
del new_data
elif res['type'] == 'action':
Action._exec_action(res['action'], dia or parent, datas,
context=ctx)
state = res['state']
elif res['type'] == 'print':
datas['report_id'] = res.get('report_id', False)
if res.get('get_id_from_action', False):
backup_ids = datas['ids']
datas['ids'] = datas['form']['ids']
Action.exec_report(res['report'], datas, dia or parent,
context=ctx)
datas['ids'] = backup_ids
else:
Action.exec_report(res['report'], datas, dia or parent,
context=ctx)
state = res['state']
elif res['type'] == 'state':
state = res['state']
if dia:
dia.destroy()
dia = None
try:
rpc.execute('wizard', 'delete', wiz_id)
#XXX to remove when company displayed in status bar
rpc.context_reload()
except:
pass
class WizardProgress(object):
def __init__(self, wizard_id, state, datas, parent, context):
self.res = None
self.error = False
self.wizard_id = wizard_id
self.state = state
self.datas = datas
self.parent = parent
self.context = context
self.exception = None
def run(self):
def start(wiz_id, datas, state, context):
ctx = rpc.CONTEXT.copy()
ctx.update(context)
try:
self.res = rpc.execute('wizard',
'execute', wiz_id, datas, state, ctx)
except Exception, exception:
self.error = True
self.res = False
self.exception = exception
return True
if not self.res:
self.error = True
return True
thread.start_new_thread(start,
(self.wizard_id, self.datas, self.state, self.context))
i = 0
win = None
progressbar = None
while (not self.res) and (not self.error):
time.sleep(0.1)
i += 1
if i > 10:
if not win or not progressbar:
win = gtk.Window(type=gtk.WINDOW_TOPLEVEL)
win.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
vbox = gtk.VBox(False, 0)
hbox = gtk.HBox(False, 13)
hbox.set_border_width(10)
img = gtk.Image()
img.set_from_stock('tryton-dialog-information', gtk.ICON_SIZE_DIALOG)
hbox.pack_start(img, expand=True, fill=False)
vbox2 = gtk.VBox(False, 0)
label = gtk.Label()
label.set_markup('<b>'+_('Operation in progress')+'</b>')
label.set_alignment(0.0, 0.5)
vbox2.pack_start(label, expand=True, fill=False)
vbox2.pack_start(gtk.HSeparator(), expand=True, fill=True)
vbox2.pack_start(gtk.Label(_("Please wait,\n" \
"this operation may take a while...")),
expand=True, fill=False)
hbox.pack_start(vbox2, expand=True, fill=True)
vbox.pack_start(hbox)
progressbar = gtk.ProgressBar()
progressbar.set_orientation(gtk.PROGRESS_LEFT_TO_RIGHT)
vbox.pack_start(progressbar, expand=True, fill=False)
win.add(vbox)
win.set_transient_for(self.parent)
win.show_all()
progressbar.pulse()
gtk.main_iteration()
if win:
win.destroy()
gtk.main_iteration()
if self.exception:
common.process_exception(self.exception, self.parent)
return self.res