diff --git a/CHANGELOG b/CHANGELOG index 27d5dfb6a5..4676459d22 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Convert many popup to be no-modal * Add window manager for: - replace current window - prevent simmilar window diff --git a/tryton/action/main.py b/tryton/action/main.py index 8ece9a1443..9a4912b8ed 100644 --- a/tryton/action/main.py +++ b/tryton/action/main.py @@ -3,7 +3,6 @@ import time import datetime import tryton.rpc as rpc -from tryton.wizard import Wizard from tryton.common import message, error, selection, file_open, mailto from tryton.gui.window import Window from tryton.pyson import PYSONDecoder @@ -20,7 +19,7 @@ _ = gettext.gettext class Action(object): @staticmethod - def exec_report(name, data, window, direct_print=False, email_print=False, + def exec_report(name, data, direct_print=False, email_print=False, email=None, context=None): if context is None: context = {} @@ -36,19 +35,19 @@ class Action(object): try: ids = rpc.execute(*args) except TrytonServerError, exception: - ids = common.process_exception(exception, window, *args) + ids = common.process_exception(exception, *args) if not ids: return False if ids == []: - message(_('Nothing to print!'), window) + message(_('Nothing to print!')) return False data['id'] = ids[0] args = ('report', name, 'execute', ids, data, ctx) - rpcprogress = common.RPCProgress('execute', args, window) + rpcprogress = common.RPCProgress('execute', args) try: res = rpcprogress.run() except TrytonServerError, exception: - common.process_exception(exception, window) + common.process_exception(exception) return False if not res: return False @@ -66,11 +65,11 @@ class Action(object): subject=email.get('subject'), body=email.get('body'), attachment=fp_name) else: - file_open(fp_name, type, window, print_p=print_p) + file_open(fp_name, type, print_p=print_p) return True @staticmethod - def execute(act_id, data, window, action_type=None, context=None): + def execute(act_id, data, action_type=None, context=None): if context is None: context = {} ctx = rpc.CONTEXT.copy() @@ -81,7 +80,7 @@ class Action(object): res = rpc.execute('model', 'ir.action', 'read', act_id, ['type'], ctx) except TrytonServerError, exception: - common.process_exception(exception, window) + common.process_exception(exception) return if not res: raise Exception, 'ActionNotFound' @@ -90,12 +89,12 @@ class Action(object): res = rpc.execute('model', action_type, 'search_read', [('action', '=', act_id)], 0, 1, None, None, ctx) except TrytonServerError, exception: - common.process_exception(exception, window) + common.process_exception(exception) return - Action._exec_action(res, window, data) + Action._exec_action(res, data) @staticmethod - def _exec_action(action, window, data=None, context=None): + def _exec_action(action, data=None, context=None): if context is None: context = {} if data is None: @@ -145,30 +144,22 @@ class Action(object): res_model = action.get('res_model', data.get('res_model')) res_id = action.get('res_id', data.get('res_id')) - Window.create(view_ids, res_model, res_id, domain, window, + Window.create(view_ids, res_model, res_id, domain, action_ctx, view_mode, name=name, limit=action.get('limit'), auto_refresh=action.get('auto_refresh'), search_value=search_value, icon=(action.get('icon.rec_name') or '')) elif action['type'] == 'ir.action.wizard': - if action.get('window', False): - Window.create_wizard(action['wiz_name'], data, window, - direct_print=action.get('direct_print', False), - email_print=action.get('email_print', False), - email=action.get('email'), name=action.get('name', False), - context=context, icon=(action.get('icon.rec_name') or '')) - else: - Wizard.execute(action['wiz_name'], data, window, - direct_print=action.get('direct_print', False), - email_print=action.get('email_print', False), - email=action.get('email'), context=context) - if action['wiz_name'] == 'ir.ui.view_sc.add': - from tryton.gui.main import Main - Main.get_main().shortcut_set() + Window.create_wizard(action['wiz_name'], data, + direct_print=action.get('direct_print', False), + email_print=action.get('email_print', False), + email=action.get('email'), name=action.get('name', False), + context=context, icon=(action.get('icon.rec_name') or ''), + window=action.get('window', False)) elif action['type'] == 'ir.action.report': - Action.exec_report(action['report_name'], data, window, + Action.exec_report(action['report_name'], data, direct_print=action.get('direct_print', False), email_print=action.get('email_print', False), email=action.get('email'), context=context) @@ -178,7 +169,7 @@ class Action(object): webbrowser.open(action['url'], new=2) @staticmethod - def exec_keyword(keyword, window, data=None, context=None, warning=True, + def exec_keyword(keyword, data=None, context=None, warning=True, alwaysask=False): actions = [] if 'id' in data: @@ -188,19 +179,18 @@ class Action(object): 'get_keyword', keyword, (data['model'], model_id), rpc.CONTEXT) except TrytonServerError, exception: - common.process_exception(exception, window) + common.process_exception(exception) return False keyact = {} for action in actions: keyact[action['name'].replace('_', '')] = action - res = selection(_('Select your action'), keyact, window, - alwaysask=alwaysask) + res = selection(_('Select your action'), keyact, alwaysask=alwaysask) if res: (name, action) = res - Action._exec_action(action, window, data, context=context) + Action._exec_action(action, data, context=context) return (name, action) elif not len(keyact) and warning: - message(_('No action defined!'), window) + message(_('No action defined!')) return False diff --git a/tryton/client.py b/tryton/client.py index a1a3ff2d82..f361245c7e 100644 --- a/tryton/client.py +++ b/tryton/client.py @@ -107,7 +107,7 @@ class TrytonClient(object): traceback.format_exception(exctyp, value, tb)) for path in sys.path: tb_s = tb_s.replace(path, '') - common.error(str(value), main.window, tb_s) + common.error(str(value), tb_s) sys.excepthook = excepthook diff --git a/tryton/common/common.py b/tryton/common/common.py index 51bfe2f1e3..f2608dd686 100644 --- a/tryton/common/common.py +++ b/tryton/common/common.py @@ -178,8 +178,9 @@ def refresh_langlist(lang_widget, host, port): lang_widget.set_active(index) return lang_list -def request_server(server_widget, parent): +def request_server(server_widget): result = False + parent = get_toplevel_window() dialog = gtk.Dialog( title= _('Tryton Connection'), parent=parent, @@ -239,14 +240,42 @@ def request_server(server_widget, parent): dialog.destroy() return result +def get_toplevel_window(): + windows = [x for x in gtk.window_list_toplevels() + if x.window and x.props.visible] + trans2windows = dict((x.get_transient_for(), x) for x in windows) + for window in set(windows) - set(trans2windows.iterkeys()): + return window + return trans2windows[None] -def selection(title, values, parent, alwaysask=False): +def get_sensible_widget(window): + from tryton.gui.main import Main + main = Main.get_main() + if main and window == main.window: + focus_widget = window.get_focus() + page = main.get_page() + if page and focus_widget and focus_widget.is_ancestor(page.widget): + return page.widget + return window + +def center_window(window, parent, sensible): + parent_x, parent_y = parent.window.get_origin() + window_allocation = window.get_allocation() + sensible_allocation = sensible.get_allocation() + x = (parent_x + sensible_allocation.x + + int((sensible_allocation.width - window_allocation.width) / 2)) + y = (parent_y + sensible_allocation.y + + int((sensible_allocation.height - window_allocation.height) / 2)) + window.move(x, y) + +def selection(title, values, alwaysask=False): if not values or len(values)==0: return None elif len(values)==1 and (not alwaysask): key = values.keys()[0] return (key, values[key]) + parent = get_toplevel_window() dialog = gtk.Dialog(_('Selection'), parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, @@ -300,9 +329,10 @@ def selection(title, values, parent, alwaysask=False): dialog.destroy() return res -def file_selection(title, filename='', parent=None, +def file_selection(title, filename='', action=gtk.FILE_CHOOSER_ACTION_OPEN, preview=True, multi=False, filters=None): + parent = get_toplevel_window() if action == gtk.FILE_CHOOSER_ACTION_OPEN: buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN,gtk.RESPONSE_OK) @@ -371,7 +401,7 @@ def file_selection(title, filename='', parent=None, win.destroy() return filenames -def file_open(filename, type, parent, print_p=False): +def file_open(filename, type, print_p=False): if os.name == 'nt': operation = 'open' if print_p: @@ -379,7 +409,7 @@ def file_open(filename, type, parent, print_p=False): try: os.startfile(os.path.normpath(filename), operation) except WindowsError: - save_name = file_selection(_('Save As...'), parent=parent, + save_name = file_selection(_('Save As...'), action=gtk.FILE_CHOOSER_ACTION_SAVE) if save_name: file_p = open(filename, 'rb') @@ -414,7 +444,7 @@ def file_open(filename, type, parent, print_p=False): #TODO add dialog box pass if not cmd: - save_name = file_selection(_('Save As...'), parent=parent, + save_name = file_selection(_('Save As...'), action=gtk.FILE_CHOOSER_ACTION_SAVE) if save_name: file_p = open(filename, 'rb') @@ -508,8 +538,8 @@ class UniqueDialog(object): if self.running: return - parent = args[1] - dialog = self.build_dialog(*args) + parent = get_toplevel_window() + dialog = self.build_dialog(parent, *args) dialog.set_icon(TRYTON_ICON) self.running = True dialog.show_all() @@ -522,21 +552,21 @@ class UniqueDialog(object): class MessageDialog(UniqueDialog): - def build_dialog(self, message, parent, msg_type): + def build_dialog(self, parent, message, msg_type): dialog = gtk.MessageDialog(parent, gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, msg_type, gtk.BUTTONS_OK, message) return dialog - def __call__(self, message, parent, msg_type=gtk.MESSAGE_INFO): - super(MessageDialog, self).__call__(message, parent, msg_type) + def __call__(self, message, msg_type=gtk.MESSAGE_INFO): + super(MessageDialog, self).__call__(message, msg_type) message = MessageDialog() class WarningDialog(UniqueDialog): - def build_dialog(self, message, parent, title, buttons=gtk.BUTTONS_OK): + def build_dialog(self, parent, message, title, buttons=gtk.BUTTONS_OK): dialog = gtk.MessageDialog(parent, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_WARNING, buttons) if hasattr(dialog, 'format_secondary_markup'): @@ -558,8 +588,8 @@ class UserWarningDialog(WarningDialog): def _set_always(self, toggle): self.always = toggle.get_active() - def build_dialog(self, message, parent, title): - dialog = super(UserWarningDialog, self).build_dialog(message, parent, + def build_dialog(self, parent, message, title): + dialog = super(UserWarningDialog, self).build_dialog(parent, message, title, gtk.BUTTONS_OK_CANCEL) check = gtk.CheckButton(_('Always ignore this warning.')) check.connect_after('toggled', self._set_always) @@ -568,9 +598,8 @@ class UserWarningDialog(WarningDialog): dialog.vbox.pack_end(alignment, True, False) return dialog - def __call__(self, message, parent, title): - response = super(UserWarningDialog, self).__call__(message, parent, - title) + def __call__(self, message, title): + response = super(UserWarningDialog, self).__call__(message, title) if response == gtk.RESPONSE_OK: if self.always: return 'always' @@ -582,7 +611,7 @@ userwarning = UserWarningDialog() class ConfirmationDialog(UniqueDialog): - def build_dialog(self, message, parent): + def build_dialog(self, parent, message): dialog = gtk.Dialog(_('Confirmation'), parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT | gtk.WIN_POS_CENTER_ON_PARENT | gtk.gdk.WINDOW_TYPE_HINT_DIALOG) @@ -596,22 +625,21 @@ class ConfirmationDialog(UniqueDialog): label = gtk.Label('%s' % (to_xml(message))) hbox.pack_start(label, True, True) dialog.vbox.pack_start(hbox) - dialog.set_transient_for(parent) return dialog class SurDialog(ConfirmationDialog): - def build_dialog(self, message, parent): - dialog = super(SurDialog, self).build_dialog(message, parent) + def build_dialog(self, parent, message): + dialog = super(SurDialog, self).build_dialog(parent, message) dialog.add_button("gtk-cancel", gtk.RESPONSE_CANCEL) dialog.add_button("gtk-ok", gtk.RESPONSE_OK | gtk.CAN_DEFAULT | gtk.HAS_DEFAULT) dialog.set_default_response(gtk.RESPONSE_OK) return dialog - def __call__(self, message, parent): - response = super(SurDialog, self).__call__(message, parent) + def __call__(self, message): + response = super(SurDialog, self).__call__(message) return response == gtk.RESPONSE_OK sur = SurDialog() @@ -625,8 +653,8 @@ class Sur3BDialog(ConfirmationDialog): gtk.RESPONSE_CANCEL: 'cancel' } - def build_dialog(self, message, parent): - dialog = super(Sur3BDialog, self).build_dialog(message, parent) + def build_dialog(self, parent, message): + dialog = super(Sur3BDialog, self).build_dialog(parent, message) dialog.add_button("gtk-cancel", gtk.RESPONSE_CANCEL) dialog.add_button("gtk-no", gtk.RESPONSE_NO) dialog.add_button("gtk-yes", gtk.RESPONSE_YES | gtk.CAN_DEFAULT @@ -634,8 +662,8 @@ class Sur3BDialog(ConfirmationDialog): dialog.set_default_response(gtk.RESPONSE_YES) return dialog - def __call__(self, message, parent): - response = super(Sur3BDialog, self).__call__(message, parent) + def __call__(self, message): + response = super(Sur3BDialog, self).__call__(message) return self.response_mapping.get(response, 'cancel') sur_3b = Sur3BDialog() @@ -643,7 +671,7 @@ sur_3b = Sur3BDialog() class AskDialog(UniqueDialog): - def build_dialog(self, question, parent, visibility): + def build_dialog(self, parent, question, visibility): win = gtk.Dialog('Tryton', parent, gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, @@ -666,12 +694,12 @@ class AskDialog(UniqueDialog): win.vbox.pack_start(hbox) return win - def __call__(self, question, parent, visibility=True): + def __call__(self, question, visibility=True): if self.running: return - dialog = self.build_dialog(question, parent, - visibility=visibility) + parent = get_toplevel_window() + dialog = self.build_dialog(parent, question, visibility=visibility) dialog.set_icon(TRYTON_ICON) self.running = True dialog.show_all() @@ -689,7 +717,7 @@ ask = AskDialog() class ConcurrencyDialog(UniqueDialog): - def build_dialog(self, resource, parent, obj_id, context): + def build_dialog(self, parent, resource, obj_id, context): dialog = gtk.Dialog(_('Concurrency Exception'), parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT | gtk.WIN_POS_CENTER_ON_PARENT | gtk.gdk.WINDOW_TYPE_HINT_DIALOG) @@ -725,9 +753,8 @@ class ConcurrencyDialog(UniqueDialog): dialog.add_action_widget(write_button, gtk.RESPONSE_OK) return dialog - def __call__(self, resource, obj_id, context, parent): - # parent must be the second parameter - res = super(ConcurrencyDialog, self).__call__(resource, parent, obj_id, + def __call__(self, resource, obj_id, context): + res = super(ConcurrencyDialog, self).__call__(resource, obj_id, context) if res == gtk.RESPONSE_OK: @@ -735,7 +762,7 @@ class ConcurrencyDialog(UniqueDialog): if res == gtk.RESPONSE_APPLY: from tryton.gui.window import Window Window.create(False, resource, res_id=obj_id, - domain=[('id', '=', obj_id)], window=parent, + domain=[('id', '=', obj_id)], context=context, mode=['form', 'tree']) return False @@ -744,7 +771,7 @@ concurrency = ConcurrencyDialog() class ErrorDialog(UniqueDialog): - def build_dialog(self, title, parent, details): + def build_dialog(self, parent, title, details): dialog = gtk.Dialog(_('Error'), parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) dialog.set_has_separator(True) @@ -813,20 +840,21 @@ class ErrorDialog(UniqueDialog): dialog.set_size_request(600, 400) return dialog - def __call__(self, title, parent, details): + def __call__(self, title, details): if title == details: title = '' log = logging.getLogger('common.message') log.error(details) - response = super(ErrorDialog, self).__call__(title, parent, details) + response = super(ErrorDialog, self).__call__(title, details) if response == gtk.RESPONSE_OK: - send_bugtracker(details, parent) + send_bugtracker(details) error = ErrorDialog() -def send_bugtracker(msg, parent): +def send_bugtracker(msg): from tryton import rpc + parent = get_toplevel_window() win = gtk.Dialog(_('Bug Tracker'), parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, @@ -909,7 +937,7 @@ def send_bugtracker(msg, parent): server.set('issue' + str(issue_id), *['nosy=+' + user]) message(_('The same bug was already reported by another user.\n' \ 'To keep you informed your username is added to the nosy-list of this issue') + \ - '%s' % issue_id, parent) + '%s' % issue_id) else: # create a new issue for this error-message # first create message @@ -919,49 +947,47 @@ def send_bugtracker(msg, parent): issue_id = server.create('issue', *['messages=' + str(msg_id), 'nosy=' + user, 'title=' + title, 'priority=bug']) message(_('Created new bug with ID ') + \ - 'issue%s' % issue_id, parent) + 'issue%s' % issue_id) webbrowser.open(CONFIG['roundup.url'] + 'issue%s' % issue_id, new=2) except (socket.error, xmlrpclib.Fault), exception: if (isinstance(exception, xmlrpclib.Fault) and 'roundup.cgi.exceptions.Unauthorised' in exception.faultString): - message(_('Connection error!\nBad username or password!'), - parent) + message(_('Connection error!\nBad username or password!')) return send_bugtracker(msg, parent) tb_s = reduce(lambda x, y: x + y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback)) - message(_('Exception:') + '\n' + tb_s, parent, - msg_type=gtk.MESSAGE_ERROR) + message(_('Exception:') + '\n' + tb_s, msg_type=gtk.MESSAGE_ERROR) def to_xml(string): return string.replace('&','&').replace('<','<').replace('>','>') PLOCK = Lock() -def process_exception(exception, parent, *args): +def process_exception(exception, *args): global _USERNAME, _DATABASE, _SOCK if isinstance(exception, TrytonError): if exception.ex_type == 'BadFingerprint': - warning(_('The server fingerprint has changed since last' - ' connection!\nThe application will stop connecting to this' - ' server until its fingerprint is fixed.'), - parent, _('Security risk!')) + warning( + _('The server fingerprint has changed since last connection!\n' + 'The application will stop connecting to this server ' + 'until its fingerprint is fixed.'), _('Security risk!')) from tryton.gui.main import Main Main.sig_quit() sys.exit() elif exception.ex_type == 'NotLogged': if not rpc._SOCK: message(_('Connection error!\n' \ - 'Unable to connect to the server!'), parent) + 'Unable to connect to the server!')) return False elif isinstance(exception, TrytonServerError): if exception.ex_type == 'UserWarning': msg = '' if len(exception.args) > 4: msg = exception.args[3] - res = userwarning(str(msg), parent, str(exception.args[2])) + res = userwarning(str(msg), str(exception.args[2])) if res in ('always', 'ok'): args2 = ('model', 'res.user.warning', 'create', { 'user': rpc._USER, @@ -971,33 +997,32 @@ def process_exception(exception, parent, *args): try: rpc.execute(*args2) except TrytonServerError, exception: - process_exception(exception, parent, *args2) + process_exception(exception, *args2) if args: try: return rpc.execute(*args) except TrytonServerError, exception: - return process_exception(exception, parent, *args) + return process_exception(exception, *args) return True return False elif exception.ex_type == 'UserError': msg = '' if len(exception.args) > 3: msg = exception.args[2] - warning(str(msg), parent, str(exception.args[1])) + warning(str(msg), str(exception.args[1])) return False elif exception.ex_type == 'ConcurrencyException': if len(args) >= 6: - if concurrency(args[1], args[3][0], args[5], parent): + if concurrency(args[1], args[3][0], args[5]): if '_timestamp' in args[5]: del args[5]['_timestamp'] try: return rpc.execute(*args) except TrytonServerError, exception: - return process_exception(exception, parent, *args) + return process_exception(exception, *args) return False else: - message(_('Concurrency Exception'), parent, - msg_type=gtk.MESSAGE_ERROR) + message(_('Concurrency Exception'), msg_type=gtk.MESSAGE_ERROR) return False elif exception.ex_type == 'NotLogged': if not PLOCK.acquire(False): @@ -1006,7 +1031,7 @@ def process_exception(exception, parent, *args): port = rpc._SOCK.port try: while True: - password = ask(_('Password:'), parent, visibility=False) + password = ask(_('Password:'), visibility=False) if password is None: continue res = rpc.login(rpc._USERNAME, password, hostname, port, @@ -1015,7 +1040,7 @@ def process_exception(exception, parent, *args): Main.get_main().refresh_ssl() if res == -1: message(_('Connection error!\n' \ - 'Unable to connect to the server!'), parent) + 'Unable to connect to the server!')) return False if res < 0: continue @@ -1023,7 +1048,7 @@ def process_exception(exception, parent, *args): try: return rpc.execute(*args) except TrytonServerError, exception: - return process_exception(exception, parent, *args) + return process_exception(exception, *args) return True finally: PLOCK.release() @@ -1031,7 +1056,7 @@ def process_exception(exception, parent, *args): msg = '' if len(exception.args) > 2: msg = exception.args[1] - warning(msg, parent, _('Network Error!')) + warning(msg, _('Network Error!')) return False if isinstance(exception, TrytonServerError): @@ -1039,7 +1064,7 @@ def process_exception(exception, parent, *args): else: error_title = str(exception) error_detail = traceback.format_exc() - error(error_title, parent, error_detail) + error(error_title, error_detail) return False def node_attributes(node): @@ -1151,10 +1176,10 @@ class DBProgress(object): class RPCProgress(object): - def __init__(self, method, args, parent): + def __init__(self, method, args): self.method = method self.args = args - self.parent = parent + self.parent = get_toplevel_window() self.res = None self.error = False self.exception = None @@ -1176,6 +1201,8 @@ class RPCProgress(object): watch = gtk.gdk.Cursor(gtk.gdk.WATCH) self.parent.window.set_cursor(watch) + parent_sensitive = self.parent.props.sensitive + self.parent.props.sensitive = False i = 0 win = None progressbar = None @@ -1219,10 +1246,12 @@ class RPCProgress(object): win.window.set_cursor(watch) with gtk.gdk.lock: progressbar.pulse() - with gtk.gdk.lock: - while gtk.events_pending(): - gtk.main_iteration() + if win: + with gtk.gdk.lock: + while gtk.events_pending(): + gtk.main_iteration() time.sleep(0.1) + self.parent.props.sensitive = parent_sensitive self.parent.window.set_cursor(None) if win: win.destroy() diff --git a/tryton/gui/main.py b/tryton/gui/main.py index 4475136d25..5a957df654 100644 --- a/tryton/gui/main.py +++ b/tryton/gui/main.py @@ -17,7 +17,6 @@ from tryton.config import CONFIG, TRYTON_ICON, PIXMAPS_DIR, DATA_DIR, \ import tryton.common as common from tryton.action import Action from tryton.exceptions import TrytonServerError, TrytonError -from tryton.wizard import Wizard from tryton.gui.window import Window from tryton.gui.window.preference import Preference from tryton.gui.window import Limit @@ -163,6 +162,7 @@ class Main(object): self.previous_pages = {} self.current_page = 0 self.last_page = 0 + self.dialogs = [] if CONFIG['client.modepda']: self.radiomenuitem_pda.set_active(True) @@ -251,6 +251,10 @@ class Main(object): self.menuitem_shortcut.set_sensitive(False) menubar.add(menuitem_shortcut) menuitem_shortcut.set_accel_path('/Shortcuts') + def shortcut_activate(widget): + if not menuitem_shortcut.get_submenu(): + self.shortcut_set() + menuitem_shortcut.connect('select', shortcut_activate) menuitem_help = gtk.MenuItem(_('_Help')) menubar.add(menuitem_help) @@ -679,13 +683,14 @@ class Main(object): def get_main(): return _MAIN[0] - def shortcut_set(self, shortcuts=None): + def shortcut_set(self): def _action_shortcut(widget, action): - Action.exec_keyword('tree_open', self.window, { + Action.exec_keyword('tree_open', { 'model': 'ir.ui.menu', 'id': action, 'ids': [action], }) + self.shortcut_unset() def _add_shortcut(widget): ids = self.menu_screen.sel_ids_get() @@ -695,7 +700,7 @@ class Main(object): values = rpc.execute('model', self.menu_screen.model_name, 'read', ids, ['rec_name'], rpc.CONTEXT) except TrytonServerError, exception: - common.process_exception(exception, self.window) + common.process_exception(exception) return try: for value in values: @@ -706,21 +711,21 @@ class Main(object): 'resource': self.menu_screen.model_name, }, rpc.CONTEXT) except TrytonServerError, exception: - common.process_exception(exception, self.window) - self.shortcut_set() + common.process_exception(exception) + self.shortcut_unset() def _manage_shortcut(widget): Window.create(False, 'ir.ui.view_sc', False, domain=[('user_id', '=', rpc._USER)], - window=self.window, mode=['tree', 'form']) + mode=['tree', 'form']) + self.shortcut_unset() - if shortcuts is None: - user = rpc._USER - try: - shortcuts = rpc.execute('model', 'ir.ui.view_sc', 'get_sc', - user, 'ir.ui.menu', rpc.CONTEXT) - except TrytonServerError: - shortcuts = [] + user = rpc._USER + try: + shortcuts = rpc.execute('model', 'ir.ui.view_sc', 'get_sc', + user, 'ir.ui.menu', rpc.CONTEXT) + except TrytonServerError: + shortcuts = [] menu = gtk.Menu() for shortcut in shortcuts: menuitem = gtk.MenuItem(shortcut['name']) @@ -735,13 +740,9 @@ class Main(object): menu.add(manage_shortcut) menu.show_all() self.menuitem_shortcut.set_submenu(menu) - self.menuitem_shortcut.set_sensitive(True) def shortcut_unset(self): - menu = gtk.Menu() - menu.show_all() - self.menuitem_shortcut.set_submenu(menu) - self.menuitem_shortcut.set_sensitive(False) + self.menuitem_shortcut.remove_submenu() def sig_accel_change(self, value): CONFIG['client.can_change_accelerators'] = value @@ -789,13 +790,13 @@ class Main(object): CONFIG['client.form_tab'] = option def sig_limit(self, widget): - Limit(self.window).run() + Limit().run() def sig_file_actions(self, widget): - FileActions(self.window).run() + FileActions().run() def sig_email(self, widget): - Email(self.window).run() + Email().run() def sig_win_next(self, widget): page = self.notebook.get_current_page() @@ -810,7 +811,7 @@ class Main(object): def sig_user_preferences(self, widget): if not self.close_pages(): return False - win = Preference(rpc._USER, self.window) + win = Preference(rpc._USER) if win.run(): rpc.context_reload() prefs = rpc.execute('model', 'res.user', @@ -823,13 +824,12 @@ class Main(object): translate.setlang(prefs['language'], prefs.get('locale')) if CONFIG['client.lang'] != prefs['language']: self.set_menubar() - self.shortcut_set() + self.shortcut_unset() self.set_statusbar() self.request_set() self.sig_win_menu() CONFIG['client.lang'] = prefs['language'] CONFIG.save() - self.window.present() self.sig_win_menu() return True @@ -842,7 +842,7 @@ class Main(object): ctx.update(rpc.CONTEXT) ctx['active_test'] = False return Window.create(None, 'res.request', False, [ ], - mode=['form', 'tree'], window=self.window, context=ctx) + mode=['form', 'tree'], context=ctx) def sig_request_open(self, widget): ctx = {} @@ -851,13 +851,13 @@ class Main(object): try: ids1, ids2 = self.request_set(True) except TrytonServerError, exception: - if common.process_exception(exception, self.window): + if common.process_exception(exception): ids1, ids2 = self.request_set(True) else: raise ids = ids1 + ids2 return Window.create(False, 'res.request', ids, [ ], - mode=['tree', 'form'], window=self.window, context=ctx) + mode=['tree', 'form'], context=ctx) def request_set(self, exception=False): try: @@ -887,19 +887,17 @@ class Main(object): return if not res: try: - dblogin = DBLogin(self.window) - res = dblogin.run(self.window) + res = DBLogin().run() except TrytonError, exception: if exception.ex_type == 'QueryCanceled': return False except TrytonServerError, exception: - common.process_exception(exception, self.window) + common.process_exception(exception) return - self.window.present() try: log_response = rpc.login(*res) except TrytonServerError, exception: - common.process_exception(exception, self.window) + common.process_exception(exception) return rpc.context_reload() self.refresh_ssl() @@ -921,20 +919,20 @@ class Main(object): translate.setlang(prefs['language'], prefs.get('locale')) if CONFIG['client.lang'] != prefs['language']: self.set_menubar() - self.shortcut_set() + self.shortcut_unset() self.set_statusbar() self.request_set() CONFIG['client.lang'] = prefs['language'] CONFIG.save() elif log_response == -1: common.message(_('Connection error!\n' \ - 'Unable to connect to the server!'), self.window) + 'Unable to connect to the server!')) elif log_response == -2: common.message(_('Connection error!\n' \ - 'Bad username or password!'), self.window) + 'Bad username or password!')) return self.sig_login() - if not self.menuitem_shortcut.get_property('sensitive'): - self.shortcut_set() + self.shortcut_unset() + self.menuitem_shortcut.set_sensitive(True) self.menuitem_user.set_sensitive(True) #self.menuitem_form.set_sensitive(True) self.menuitem_plugins.set_sensitive(True) @@ -947,8 +945,7 @@ class Main(object): if self.notebook.get_n_pages(): if not common.sur( _('The following action requires to close all tabs.\n' - 'Do you want to continue?'), - parent=self.window): + 'Do you want to continue?')): return False res = True while res: @@ -975,6 +972,7 @@ class Main(object): self.sb_servername.set_text('') self.sb_requests.set_text('') self.shortcut_unset() + self.menuitem_shortcut.set_sensitive(False) self.menuitem_user.set_sensitive(False) #self.menuitem_form.set_sensitive(False) self.menuitem_plugins.set_sensitive(False) @@ -996,13 +994,13 @@ class Main(object): self.tooltips.set_tip(self.secure_img, '') def sig_tips(self, *args): - Tips(self.window) + Tips() def sig_about(self, widget): - About(self.window) + About() def sig_shortcuts(self, widget): - Shortcuts(self.window).run() + Shortcuts().run() def menu_toggle(self, nohide=False): has_focus = True @@ -1041,7 +1039,7 @@ class Main(object): try: prefs = rpc.execute(*args) except TrytonServerError, exception: - prefs = common.process_exception(exception, self.window, *args) + prefs = common.process_exception(exception, *args) if not prefs: return False self.sb_username.set_text(prefs.get('status_bar', '')) @@ -1052,14 +1050,14 @@ class Main(object): return False common.warning(_('You can not log into the system!\n' \ 'Verify if you have a menu defined on your user.'), - 'Access Denied!', self.window) + 'Access Denied!') rpc.logout() self.refresh_ssl() return False act_id = prefs[menu_type] if except_id and act_id == except_id: return act_id - Action.execute(act_id, {}, self.window) + Action.execute(act_id, {}) return act_id def sig_home_new(self, widget=None, quiet=True, except_id=False, @@ -1076,7 +1074,7 @@ class Main(object): 'ids': self.pages[page].ids_get(), 'id': self.pages[page].id_get(), } - tryton.plugins.execute(datas, self.window) + tryton.plugins.execute(datas) @classmethod def sig_quit(cls, widget=None): @@ -1244,24 +1242,30 @@ class Main(object): def _sig_page_changt(self, notebook, page, page_num): self.last_page = self.current_page + last_form = self.get_page(self.current_page) + if last_form: + for dialog in last_form.dialogs: + dialog.hide() + self.current_page = self.notebook.get_current_page() - current_form = self.get_page() + current_form = self.get_page(self.current_page) + for dialog in current_form.dialogs: + dialog.show() def sig_db_new(self, widget): if not self.sig_logout(widget): return False dia = DBCreate(CONFIG['login.server'], int(CONFIG['login.port']), sig_login=self.sig_login) - res = dia.run(self.window) + res = dia.run() if res: CONFIG.save() return res - def sig_db_drop(self, widget): + def sig_db_drop(self, widget=None): if not self.sig_logout(widget): return False - dialog = DBBackupDrop(self.window, function='drop') - url, dbname, passwd = dialog.run(self.window) + url, dbname, passwd = DBBackupDrop(function='drop').run() if not dbname: rpc.logout() Main.get_main().refresh_ssl() @@ -1269,44 +1273,42 @@ class Main(object): host, port = url.rsplit(':', 1) sure = common.sur_3b(_("You are going to delete a Tryton " \ - "database.\nAre you really sure to proceed?"), self.window) + "database.\nAre you really sure to proceed?")) if sure == "ko" or sure == "cancel": return rpcprogress = common.RPCProgress('db_exec', (host, int(port), 'drop', - dbname, passwd), self.window) + dbname, passwd)) try: rpcprogress.run() except TrytonServerError, exception: self.refresh_ssl() if exception.args[0] == "AccessDenied": common.warning(_("Wrong Tryton Server Password" \ - "\nPlease try again."), self.window, + "\nPlease try again."), _('Access denied!')) - self.sig_db_drop(self.window) + self.sig_db_drop() else: - common.warning(_('Database drop failed with ' \ - 'error message:\n') + str(exception.args[0]), \ - self.window, _('Database drop failed!')) + common.warning(_('Database drop failed with error message:\n') + + str(exception.args[0]), _('Database drop failed!')) return self.refresh_ssl() - common.message(_("Database dropped successfully!"), \ - parent=self.window) + common.message(_("Database dropped successfully!")) def sig_db_restore(self, widget): if not self.sig_logout(widget): return False - filename = common.file_selection(_('Open Backup File to Restore...'), \ - parent=self.window, preview=False) + filename = common.file_selection(_('Open Backup File to Restore...'), + preview=False) if not filename: return - dialog = DBRestore(self.window, filename=filename) - url, dbname, passwd, update = dialog.run(self.window) + dialog = DBRestore(filename=filename) + url, dbname, passwd, update = dialog.run() if dbname: with open(filename, 'rb') as file_p: data_b64 = base64.encodestring(file_p.read()) host, port = url.rsplit(':' , 1) rpcprogress = common.RPCProgress('db_exec', (host, int(port), - 'restore', dbname, passwd, data_b64, update), self.window) + 'restore', dbname, passwd, data_b64, update)) try: res = rpcprogress.run() except TrytonServerError, exception: @@ -1316,31 +1318,29 @@ class Main(object): common.warning(_("It is not possible to restore a " \ "password protected database.\n" \ "Backup and restore needed to be proceed " \ - "manual."), self.window, \ + "manual."), _('Database is password protected!')) elif exception.args[0] == "AccessDenied": common.warning(_("Wrong Tryton Server Password.\n" \ - "Please try again."), self.window, \ + "Please try again."), _('Access denied!')) - self.sig_db_restore(self.window) + self.sig_db_restore() else: common.warning(_('Database restore failed with ' \ 'error message:\n') + str(exception.args[0]), \ - self.window, _('Database restore failed!')) + _('Database restore failed!')) return self.refresh_ssl() if res: - common.message(_("Database restored successfully!"), \ - parent=self.window) + common.message(_("Database restored successfully!")) else: - common.message(_('Database restore failed!'), \ - parent=self.window) + common.message(_('Database restore failed!')) def sig_db_dump(self, widget): if not self.sig_logout(widget): return False - dialog = DBBackupDrop(self.window, function='backup') - url, dbname, passwd = dialog.run(self.window) + dialog = DBBackupDrop(function='backup') + url, dbname, passwd = dialog.run() if not (dbname and url and passwd): rpc.logout() @@ -1349,7 +1349,7 @@ class Main(object): host, port = url.rsplit(':', 1) rpcprogress = common.RPCProgress('db_exec', (host, int(port), 'dump', - dbname, passwd), self.window) + dbname, passwd)) try: dump_b64 = rpcprogress.run() except TrytonServerError, exception: @@ -1357,16 +1357,16 @@ class Main(object): common.warning(_("It is not possible to dump a password " \ "protected Database.\nBackup and restore " \ "needed to be proceed manual."), - self.window, _('Database is password protected!')) + _('Database is password protected!')) elif exception.args[0] == "AccessDenied": common.warning(_("Wrong Tryton Server Password.\n" \ - "Please try again."), self.window, + "Please try again."), _('Access denied!')) - self.sig_db_dump(self.window) + self.sig_db_dump() else: common.warning(_('Database dump failed with ' \ - 'error message:\n') + str(exception.args[0]), \ - self.window, _('Database dump failed!')) + 'error message:\n') + str(exception.args[0]), + _('Database dump failed!')) rpc.logout() Main.get_main().refresh_ssl() return @@ -1374,16 +1374,14 @@ class Main(object): self.refresh_ssl() dump = base64.decodestring(dump_b64) - filename = common.file_selection(_('Save As...'), \ - action=gtk.FILE_CHOOSER_ACTION_SAVE, parent=self.window, \ - preview=False, - filename=dbname + '-' + time.strftime('%Y%m%d%H%M') + '.dump') + filename = common.file_selection(_('Save As...'), + action=gtk.FILE_CHOOSER_ACTION_SAVE, preview=False, + filename=dbname + '-' + time.strftime('%Y%m%d%H%M') + '.dump') if filename: with open(filename, 'wb') as file_: file_.write(dump) - common.message(_("Database backuped successfully!"), \ - parent=self.window) + common.message(_("Database backuped successfully!")) else: rpc.logout() Main.get_main().refresh_ssl() @@ -1435,9 +1433,8 @@ class Main(object): mode = ['form', 'tree'] try: Window.create(view_ids, model, res_id=res_id, domain=domain, - window=self.window, context=context, mode=mode, - name=name, limit=limit, auto_refresh=auto_refresh, - search_value=search_value) + context=context, mode=mode, name=name, limit=limit, + auto_refresh=auto_refresh, search_value=search_value) except Exception: # Prevent crashing the client return @@ -1456,14 +1453,9 @@ class Main(object): except ValueError: return try: - if window: - Window.create_wizard(wizard, data, self.window, - direct_print=direct_print, email_print=email_print, - email=email, name=name, context=context) - else: - Wizard.execute(wizard, data, self.window, - direct_print=direct_print, email_print=email_print, - email=email, context=context) + Window.create_wizard(wizard, data, direct_print=direct_print, + email_print=email_print, email=email, name=name, + context=context, window=window) except Exception: # Prevent crashing the client return @@ -1481,9 +1473,8 @@ class Main(object): except ValueError: return try: - Action.exec_report(report, data, self.window, - direct_print=direct_print, email_print=email_print, - email=email, context=context) + Action.exec_report(report, data, direct_print=direct_print, + email_print=email_print, email=email, context=context) except Exception: # Prevent crashing the client return diff --git a/tryton/gui/window/about.py b/tryton/gui/window/about.py index e39af38e41..84d3ecaa03 100644 --- a/tryton/gui/window/about.py +++ b/tryton/gui/window/about.py @@ -4,9 +4,10 @@ import gtk import gettext import os +import webbrowser from tryton.config import TRYTON_ICON, PIXMAPS_DIR, DATA_DIR from tryton.version import VERSION, WEBSITE -import webbrowser +from tryton.common import get_toplevel_window COPYRIGHT = '''\ Copyright (C) 2010-2011 Nicolas Évrard. @@ -710,11 +711,12 @@ _ = gettext.gettext class About(object): - def __init__(self, parent): + def __init__(self): gtk.about_dialog_set_email_hook(lambda widget, link: webbrowser.open(link, new=2)) gtk.about_dialog_set_url_hook(lambda widget, link: webbrowser.open(link, new=2)) + parent = get_toplevel_window() self.win = gtk.AboutDialog() self.win.set_transient_for(parent) self.win.set_name('Tryton') diff --git a/tryton/gui/window/attachment.py b/tryton/gui/window/attachment.py index 1724a2df8a..4c83734452 100644 --- a/tryton/gui/window/attachment.py +++ b/tryton/gui/window/attachment.py @@ -8,19 +8,17 @@ from tryton.gui.window.win_form import WinForm class Attachment(object): "Attachment window" - def __init__(self, model_name, record_id, parent): + def __init__(self, model_name, record_id): self.resource = '%s,%s' % (model_name, record_id) - self.parent = parent def run(self): - screen = Screen('ir.attachment', self.parent, domain=[ + screen = Screen('ir.attachment', domain=[ ('resource', '=', self.resource), ], mode=['tree', 'form'], context={ 'resource': self.resource, }, exclude_field='resource') screen.search_filter() - win = WinForm(screen, self.parent, view_type='tree') - if win.run(): - screen.group.save() - self.parent.present() - win.destroy() + def callback(result): + if result: + screen.group.save() + WinForm(screen, callback, view_type='tree') diff --git a/tryton/gui/window/board.py b/tryton/gui/window/board.py index 038dfff433..c1da0f524a 100644 --- a/tryton/gui/window/board.py +++ b/tryton/gui/window/board.py @@ -40,7 +40,7 @@ class Board(SignalEvent, TabContent): '/Form/Close'), ] - def __init__(self, model, window, view_id, context=None, name=False, + def __init__(self, model, view_id, context=None, name=False, auto_refresh=False): super(Board, self).__init__() @@ -48,14 +48,15 @@ class Board(SignalEvent, TabContent): view = rpc.execute('model', 'ir.ui.view', 'read', view_id, ['arch'], context) except TrytonServerError, exception: - common.process_exception(exception, window) + common.process_exception(exception) raise - self.board = ViewBoard(view['arch'], window, context=context) + self.board = ViewBoard(view['arch'], context=context) self.model = model self.view_id = view_id self.context = context self.auto_refresh = auto_refresh + self.dialogs = [] if not name: self.name = self.board.name else: diff --git a/tryton/gui/window/dbcreate.py b/tryton/gui/window/dbcreate.py index 5c48316073..29e7998427 100644 --- a/tryton/gui/window/dbcreate.py +++ b/tryton/gui/window/dbcreate.py @@ -54,13 +54,13 @@ class DBCreate(object): "Click on 'Change' to change the address.")) return state - def server_change(self, widget, parent): + def server_change(self, widget): """ This method checks the server connection via host and port. If the connection is successfull, it query the language list and pass true state to the GUI. Otherwise it pass false state to the GUI. """ - res = common.request_server(self.entry_server_connection, parent) + res = common.request_server(self.entry_server_connection) if not res: return False host, port = res @@ -287,7 +287,8 @@ class DBCreate(object): self.dialog.vbox.pack_start(dialog_vbox) self.sig_login = sig_login - def run(self, parent): + def run(self): + parent = common.get_toplevel_window() self.dialog.set_default_response(gtk.RESPONSE_OK) self.dialog.set_transient_for(parent) self.dialog.show_all() @@ -296,7 +297,7 @@ class DBCreate(object): change_button = self.button_server_change admin_passwd = self.entry_adminpasswd admin_passwd2 = self.entry_adminpasswd2 - change_button.connect_after('clicked', self.server_change, self.dialog) + change_button.connect_after('clicked', self.server_change) if self.host and self.port: url = '%s:%d' % (self.host, self.port) @@ -327,20 +328,19 @@ class DBCreate(object): common.warning(_('The database name is restricted to ' \ 'alpha-nummerical characters and "_" (underscore). ' \ 'Avoid all accents, space ' \ - 'and any other special characters.'), self.dialog, \ + 'and any other special characters.'), _('Wrong characters in database name!')) continue elif admin_passwd.get_text() != admin_passwd2.get_text(): common.warning( _("The new admin password " \ "doesn't match the confirmation field.\n"), - self.dialog, _("Passwords doesn't match!")) continue elif not admin_passwd.get_text(): common.warning(_("Admin password and confirmation are " \ "required to create a new database."), \ - self.dialog, _('Missing admin password!')) + _('Missing admin password!')) continue elif url_m.group(1) \ and int(url_m.group(2)) \ @@ -352,12 +352,12 @@ class DBCreate(object): exist = rpc.db_exec(url_m.group(1), int(url_m.group(2)), 'db_exist', dbname) except TrytonServerError, exception: - common.process_exception(exception, self.dialog) + common.process_exception(exception) continue if exist: common.warning(_("A database with the same name " \ "already exists.\n" \ - "Try another database name."), self.dialog, + "Try another database name."), _("This database name already exist!")) self.entry_dbname.set_text("") self.entry_dbname.grab_focus() @@ -368,14 +368,13 @@ class DBCreate(object): try: rpcprogress = common.RPCProgress('db_exec', (host, int(port), 'create', dbname, passwd, - langreal, admin_passwd.get_text()), - self.dialog) + langreal, admin_passwd.get_text())) rpcprogress.run() except TrytonServerError, exception: if str(exception.args[0]) == "AccessDenied": common.warning(_("Sorry, wrong password for " \ "the Tryton server. Please try again."), - self.dialog, _("Access denied!")) + _("Access denied!")) self.entry_serverpasswd.set_text("") self.entry_serverpasswd.grab_focus() continue @@ -387,7 +386,7 @@ class DBCreate(object): "Please check the error message for " \ "possible informations.\n" \ "Error message:\n") + str(exception.args[0]), - self.dialog, _("Error creating database!")) + _("Error creating database!")) parent.present() self.dialog.destroy() rpc.logout() diff --git a/tryton/gui/window/dbdumpdrop.py b/tryton/gui/window/dbdumpdrop.py index 729a1478f6..21819e95c2 100644 --- a/tryton/gui/window/dbdumpdrop.py +++ b/tryton/gui/window/dbdumpdrop.py @@ -41,9 +41,8 @@ class DBBackupDrop(object): return dbs @staticmethod - def refreshlist_ask(widget, server_widget, db_widget, label, db_progress, - parent=None): - res = common.request_server(server_widget, parent) + def refreshlist_ask(widget, server_widget, db_widget, label, db_progress): + res = common.request_server(server_widget) if not res: return None host, port = res @@ -71,7 +70,7 @@ class DBBackupDrop(object): else: self.button_ok.set_sensitive(False) - def __init__(self, parent, function=None): + def __init__(self, function=None): # This widget is used for creating and droping a database! if function =="backup": dialog_title = _("Backup a database") @@ -88,11 +87,10 @@ class DBBackupDrop(object): else: return None - self.dialog = gtk.Dialog( \ - title = dialog_title, \ - parent = parent, \ - flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT \ - | gtk.WIN_POS_CENTER_ON_PARENT,) + self.parent = common.get_toplevel_window() + self.dialog = gtk.Dialog(title=dialog_title, parent=self.parent, + flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT + | gtk.WIN_POS_CENTER_ON_PARENT) self.dialog.set_has_separator(True) self.dialog.set_icon(TRYTON_ICON) self.dialog.connect("key-press-event", self.event_show_button_ok) @@ -195,9 +193,8 @@ class DBBackupDrop(object): self.entry_serverpasswd.grab_focus() self.dialog.vbox.pack_start(self.dialog_vbox) - def run(self, parent): + def run(self): self.dialog.set_default_response(gtk.RESPONSE_OK) - self.dialog.set_transient_for(parent) self.dialog.show_all() pass_widget = self.entry_serverpasswd @@ -215,8 +212,8 @@ class DBBackupDrop(object): CONFIG['login.server'], CONFIG['login.port']) change_button = self.button_server_change - change_button.connect_after('clicked', DBBackupDrop.refreshlist_ask, \ - server_widget, db_widget, label, db_progress, self.dialog) + change_button.connect_after('clicked', DBBackupDrop.refreshlist_ask, + server_widget, db_widget, label, db_progress) while True: database = False @@ -232,7 +229,7 @@ class DBBackupDrop(object): self.dialog.destroy() rpc.logout() break - parent.present() + self.parent.present() self.dialog.destroy() return (url, database, passwd) diff --git a/tryton/gui/window/dblogin.py b/tryton/gui/window/dblogin.py index fc9af5fdaa..d3fa332094 100644 --- a/tryton/gui/window/dblogin.py +++ b/tryton/gui/window/dblogin.py @@ -356,9 +356,10 @@ class DBListEditor(object): class DBLogin(object): - def __init__(self, parent): + def __init__(self): # GTK Stuffs - self.dialog = gtk.Dialog(title=_('Login'), parent=parent, + self.parent = common.get_toplevel_window() + self.dialog = gtk.Dialog(title=_('Login'), parent=self.parent, flags=gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT) self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT) self.dialog.set_has_separator(True) @@ -566,7 +567,7 @@ class DBLogin(object): else: return 8070 - def run(self, parent): + def run(self): profile_name = CONFIG['login.profile'] can_use_profile = self.profiles.has_section(profile_name) if can_use_profile: @@ -637,14 +638,12 @@ class DBLogin(object): result = (self.entry_login.get_text(), self.entry_password.get_text(), host, port, database) + self.parent.present() + self.dialog.destroy() if res != gtk.RESPONSE_OK: - parent.present() - self.dialog.destroy() rpc.logout() from tryton.gui.main import Main Main.get_main().refresh_ssl() raise TrytonError('QueryCanceled') - parent.present() - self.dialog.destroy() return result diff --git a/tryton/gui/window/dbrestore.py b/tryton/gui/window/dbrestore.py index 04b077e9d2..10115494d6 100644 --- a/tryton/gui/window/dbrestore.py +++ b/tryton/gui/window/dbrestore.py @@ -55,15 +55,14 @@ class DBRestore(object): gobject.idle_add(_move_cursor) entry.stop_emission("insert-text") - def __init__(self, parent=None, filename=None): + def __init__(self, filename=None): """ Database restore widget """ - self.dialog = gtk.Dialog( \ - title = _("Restore Database"), \ - parent=parent, \ - flags = gtk.DIALOG_MODAL \ - | gtk.WIN_POS_CENTER_ON_PARENT) + self.parent = common.get_toplevel_window() + self.dialog = gtk.Dialog(title=_("Restore Database"), + parent=self.parent, flags=gtk.DIALOG_MODAL + | gtk.WIN_POS_CENTER_ON_PARENT) vbox = gtk.VBox() self.dialog.vbox.pack_start(vbox) self.tooltips = common.Tooltips() @@ -165,11 +164,10 @@ class DBRestore(object): self.entry_server_password.grab_focus() - def run(self, parent): + def run(self): """ Database Restore widget run part """ - self.dialog.set_transient_for(parent) self.dialog.show_all() self.entry_server_url.set_text('%(login.server)s:%(login.port)s' % @@ -180,9 +178,9 @@ class DBRestore(object): url = False update = False #TODO: This needs to be unified with the other widgets - self.button_server_change.connect_after('clicked', \ - lambda a, b: common.request_server(b, self.dialog), \ - self.entry_server_url) + self.button_server_change.connect_after('clicked', + lambda a, b: common.request_server(b), + self.entry_server_url) res = self.dialog.run() if res == gtk.RESPONSE_OK: database = self.entry_db_name.get_text() @@ -194,7 +192,7 @@ class DBRestore(object): self.dialog.destroy() rpc.logout() break - parent.present() + self.parent.present() self.dialog.destroy() return url, database, passwd, update diff --git a/tryton/gui/window/email.py b/tryton/gui/window/email.py index e4cb887f22..4112050f92 100644 --- a/tryton/gui/window/email.py +++ b/tryton/gui/window/email.py @@ -4,22 +4,22 @@ import gtk import gettext from tryton.config import TRYTON_ICON, CONFIG +from tryton.common import get_toplevel_window _ = gettext.gettext class Email(object): - def __init__(self, parent): - self.win = gtk.Dialog(_('Email'), parent, + def __init__(self): + self.parent = get_toplevel_window() + self.win = gtk.Dialog(_('Email'), self.parent, gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)) - self.parent = parent self.win.set_default_response(gtk.RESPONSE_OK) self.win.set_icon(TRYTON_ICON) self.win.set_has_separator(True) - self.win.set_transient_for(parent) self.win.vbox.set_spacing(3) self.win.vbox.pack_start(gtk.Label( _('Email Program Settings')), expand=False, fill=True) diff --git a/tryton/gui/window/fileactions.py b/tryton/gui/window/fileactions.py index 721f4e70b3..403365662a 100644 --- a/tryton/gui/window/fileactions.py +++ b/tryton/gui/window/fileactions.py @@ -4,7 +4,7 @@ import gtk import gettext from tryton.config import TRYTON_ICON, CONFIG -from tryton.common import safe_eval +from tryton.common import safe_eval, get_toplevel_window _ = gettext.gettext @@ -12,16 +12,15 @@ _ = gettext.gettext class FileActions(object): "File actions window" - def __init__(self, parent): - self.win = gtk.Dialog(_('File Actions'), parent, + def __init__(self): + self.parent= get_toplevel_window() + self.win = gtk.Dialog(_('File Actions'), self.parent, gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)) - self.parent = parent self.win.set_default_response(gtk.RESPONSE_OK) self.win.set_icon(TRYTON_ICON) self.win.set_has_separator(True) - self.win.set_transient_for(parent) self.win.vbox.pack_start(gtk.Label( _('Edit Files Actions')), expand=False, fill=True) self.win.vbox.pack_start(gtk.HSeparator()) diff --git a/tryton/gui/window/form.py b/tryton/gui/window/form.py index d755a5189c..3b6a8a4471 100644 --- a/tryton/gui/window/form.py +++ b/tryton/gui/window/form.py @@ -93,7 +93,7 @@ class Form(SignalEvent, TabContent): '/Form/Import Data'), ] - def __init__(self, model, window, res_id=False, domain=None, mode=None, + def __init__(self, model, res_id=False, domain=None, mode=None, view_ids=None, context=None, name=False, limit=None, auto_refresh=False, search_value=None): super(Form, self).__init__() @@ -108,18 +108,17 @@ class Form(SignalEvent, TabContent): context = {} self.model = model - self.window = window self.res_id = res_id self.domain = domain self.mode = mode self.context = context self.auto_refresh = auto_refresh self.view_ids = view_ids + self.dialogs = [] - self.screen = Screen(self.model, self.window, mode=mode, - context=self.context, view_ids=view_ids, domain=domain, - limit=limit, readonly=bool(auto_refresh), - search_value=search_value) + self.screen = Screen(self.model, mode=mode, context=self.context, + view_ids=view_ids, domain=domain, limit=limit, + readonly=bool(auto_refresh), search_value=search_value) self.screen.widget.show() if not name: @@ -159,8 +158,7 @@ class Form(SignalEvent, TabContent): try: toolbars = rpc.execute(*args) except TrytonServerError, exception: - toolbars = common.process_exception(exception, self.window, - *args) + toolbars = common.process_exception(exception, *args) toolbars = toolbars if toolbars else {} self._toolbar_cache[self.model] = toolbars return self._toolbar_cache[self.model] @@ -174,7 +172,6 @@ class Form(SignalEvent, TabContent): if not isinstance(value, Form): return False return (self.model == value.model - and self.window == value.window and self.res_id == value.res_id and self.domain == value.domain and self.mode == value.mode @@ -188,7 +185,8 @@ class Form(SignalEvent, TabContent): def sig_goto(self, widget=None): if not self.modified_save(): return - win = gtk.Dialog(_('Go to ID'), self.window, + parent = common.get_toplevel_window() + win = gtk.Dialog(_('Go to ID'), parent, gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)) @@ -224,7 +222,7 @@ class Form(SignalEvent, TabContent): if response == gtk.RESPONSE_OK: self.screen.display(locale.atoi(entry.get_text()), set_cursor=True) win.destroy() - self.window.present() + parent.present() def destroy(self): self.screen.signal_unconnect(self) @@ -246,8 +244,7 @@ class Form(SignalEvent, TabContent): def sig_attach(self, widget=None): obj_id = self.id_get() if obj_id >= 0 and obj_id is not False: - win = Attachment(self.model, obj_id, self.window) - win.run() + Attachment(self.model, obj_id).run() else: self.message_info(_('No record selected!')) self.update_attachment_count(reload=True) @@ -295,7 +292,7 @@ class Form(SignalEvent, TabContent): try: res = rpc.execute(*args) except TrytonServerError, exception: - res = common.process_exception(exception, self.window, *args) + res = common.process_exception(exception, *args) if not res: return message_str = '' @@ -309,7 +306,7 @@ class Form(SignalEvent, TabContent): value = common.datetime_strftime(date, display_format) message_str += val + ' ' + value +'\n' message_str += _('Model:') + ' ' + self.model - message(message_str, self.window) + message(message_str) return True def sig_remove(self, widget=None): @@ -317,7 +314,7 @@ class Form(SignalEvent, TabContent): msg = _('Are you sure to remove this record?') else: msg = _('Are you sure to remove those records?') - if sur(msg, self.window): + if sur(msg): if not self.screen.remove(delete=True, force_remove=True): self.message_info(_('Records not removed!')) else: @@ -329,7 +326,7 @@ class Form(SignalEvent, TabContent): fields = {} for name, field in self.screen.group.fields.iteritems(): fields[name] = field.attrs - win = WinImport(self.model, self.window) + win = WinImport(self.model) win.run() def sig_save_as(self, widget=None): @@ -338,7 +335,7 @@ class Form(SignalEvent, TabContent): fields = {} for name, field in self.screen.group.fields.iteritems(): fields[name] = field.attrs - win = WinExport(self.model, self.ids_get(), self.window, + win = WinExport(self.model, self.ids_get(), context=self.context) win.run() @@ -360,7 +357,7 @@ class Form(SignalEvent, TabContent): try: new_ids = rpc.execute(*args) except TrytonServerError, exception: - new_ids = common.process_exception(exception, self.window, *args) + new_ids = common.process_exception(exception, *args) if new_ids: self.screen.load(new_ids) self.message_info(_('Working now on the duplicated record(s)!'), @@ -391,7 +388,7 @@ class Form(SignalEvent, TabContent): return False if test_modified and self.screen.modified(): res = sur_3b(_('This record has been modified\n' \ - 'do you want to save it ?'), self.window) + 'do you want to save it ?')) if res == 'ok': self.sig_save(None) elif res == 'ko': @@ -429,6 +426,8 @@ class Form(SignalEvent, TabContent): self.buttons['relate'].props.active = True def action_popup(self, widget): + button, = widget.get_children() + button.grab_focus() menu = widget._menu if not widget.props.active: menu.popdown() @@ -449,12 +448,12 @@ class Form(SignalEvent, TabContent): def sig_search(self, widget=None): if not self.modified_save(): return - win = WinSearch(self.model, domain=self.domain, - context=self.context, parent=self.window) - res = win.run() - if res: - self.screen.clear() - self.screen.load(res) + def callback(result): + if result: + self.screen.clear() + self.screen.load(result) + WinSearch(self.model, callback, domain=self.domain, + context=self.context) def message_info(self, message, color='red'): if message: @@ -495,8 +494,7 @@ class Form(SignalEvent, TabContent): if self.screen.modified(): value = sur_3b( _('This record has been modified\n' \ - 'do you want to save it ?'), - self.window) + 'do you want to save it ?')) if value == 'ok': return self.sig_save(None) elif value == 'ko': @@ -508,6 +506,8 @@ class Form(SignalEvent, TabContent): return True def sig_close(self, widget=None): + for dialog in self.dialogs[:]: + dialog.destroy() return self.modified_save(reload=False) def _action(self, action, atype): @@ -544,11 +544,7 @@ class Form(SignalEvent, TabContent): 'id': record_id, 'ids': record_ids, } - value = Action._exec_action(action, self.window, data, {}) - if atype in ('print', 'action'): - if self.screen: - self.screen.reload(written=True) - return value + Action._exec_action(action, data, {}) def activate_save(self): self.buttons['save'].props.sensitive = self.screen.modified() diff --git a/tryton/gui/window/limit.py b/tryton/gui/window/limit.py index f4e74a82ba..bac2ce6a58 100644 --- a/tryton/gui/window/limit.py +++ b/tryton/gui/window/limit.py @@ -4,6 +4,7 @@ import sys import gtk import gettext from tryton.config import TRYTON_ICON, CONFIG +from tryton.common import get_toplevel_window _ = gettext.gettext @@ -11,16 +12,15 @@ _ = gettext.gettext class Limit(object): 'Set Search Limit' - def __init__(self, parent): - self.win = gtk.Dialog(_('Limit'), parent, + def __init__(self): + self.parent = get_toplevel_window() + self.win = gtk.Dialog(_('Limit'), self.parent, gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)) - self.parent = parent self.win.set_default_response(gtk.RESPONSE_OK) self.win.set_icon(TRYTON_ICON) self.win.set_has_separator(True) - self.win.set_transient_for(parent) self.win.vbox.set_spacing(3) self.win.vbox.pack_start(gtk.Label( _('Search Limit Settings')), expand=False, fill=True) diff --git a/tryton/gui/window/nomodal.py b/tryton/gui/window/nomodal.py new file mode 100644 index 0000000000..41734bf714 --- /dev/null +++ b/tryton/gui/window/nomodal.py @@ -0,0 +1,27 @@ +#This file is part of Tryton. The COPYRIGHT file at the top level of +#this repository contains the full copyright notices and license terms. +from tryton.gui.main import Main +import tryton.common as common + + +class NoModal(object): + + def __init__(self): + self.parent = common.get_toplevel_window() + self.sensible_widget = common.get_sensible_widget(self.parent) + self.page = None + self.parent_focus = self.parent.get_focus() + + def register(self): + main = Main.get_main() + self.page = main.get_page() + if not self.page: + self.page = main + self.page.dialogs.append(self) + self.sensible_widget.props.sensitive = False + + def destroy(self): + self.page.dialogs.remove(self) + self.sensible_widget.props.sensitive = True + self.parent.present() + self.parent_focus.grab_focus() diff --git a/tryton/gui/window/preference.py b/tryton/gui/window/preference.py index 0aac766ca6..53b40783d3 100644 --- a/tryton/gui/window/preference.py +++ b/tryton/gui/window/preference.py @@ -16,13 +16,13 @@ _ = gettext.gettext class Preference(object): "Preference window" - def __init__(self, user, parent): - self.win = gtk.Dialog(_('Preferences'), parent, + def __init__(self, user): + self.parent = common.get_toplevel_window() + self.win = gtk.Dialog(_('Preferences'), self.parent, gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT) self.win.set_position(gtk.WIN_POS_CENTER_ON_PARENT) self.win.set_has_separator(False) self.win.set_icon(TRYTON_ICON) - self.parent = parent self.accel_group = gtk.AccelGroup() self.win.add_accel_group(self.accel_group) @@ -40,7 +40,7 @@ class Preference(object): try: view = rpc.execute(*args) except TrytonServerError, exception: - view = common.process_exception(exception, parent, *args) + view = common.process_exception(exception, *args) if not view: self.win.destroy() self.win = None @@ -49,7 +49,7 @@ class Preference(object): title = gtk.Label(_('Edit User Preferences')) title.show() self.win.vbox.pack_start(title, expand=False, fill=True) - self.screen = Screen('res.user', self.win, mode=[]) + self.screen = Screen('res.user', mode=[]) self.screen.new(default=False) self.screen.add_view(view) @@ -57,7 +57,7 @@ class Preference(object): try: preferences = rpc.execute(*args) except TrytonServerError, exception: - preferences = common.process_exception(exception, parent, *args) + preferences = common.process_exception(exception, *args) if not preferences: self.win.destroy() raise @@ -66,13 +66,13 @@ class Preference(object): self.screen.screen_container.set(self.screen.current_view.widget) self.screen.display(set_cursor=True) - width, height = self.screen.screen_container.size_get() - parent_width, parent_height = parent.get_size() - self.screen.widget.set_size_request(min(parent_width - 20, width + 20), - min(parent_height - 60, height + 25)) self.screen.widget.show() self.win.vbox.pack_start(self.screen.widget) self.win.set_title(_('Preference')) + + width, height = self.parent.get_size() + self.win.set_default_size(int(width * 0.9), int(height * 0.9)) + self.win.show() def run(self): diff --git a/tryton/gui/window/shortcuts.py b/tryton/gui/window/shortcuts.py index bdbb00f1c6..2d6bc3df01 100644 --- a/tryton/gui/window/shortcuts.py +++ b/tryton/gui/window/shortcuts.py @@ -4,6 +4,7 @@ import gtk import gettext from tryton.config import TRYTON_ICON +from tryton.common import get_toplevel_window _ = gettext.gettext @@ -11,12 +12,12 @@ _ = gettext.gettext class Shortcuts(object): 'Shortcuts window' - def __init__(self, parent): - self.dialog = gtk.Dialog(_('Keyboard Shortcuts'), parent, gtk.DIALOG_MODAL - | gtk.DIALOG_DESTROY_WITH_PARENT | gtk.WIN_POS_CENTER_ON_PARENT - | gtk.gdk.WINDOW_TYPE_HINT_DIALOG, - (gtk.STOCK_OK, gtk.RESPONSE_OK)) - self.parent = parent + def __init__(self): + self.parent = get_toplevel_window() + self.dialog = gtk.Dialog(_('Keyboard Shortcuts'), self.parent, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT + | gtk.WIN_POS_CENTER_ON_PARENT | gtk.gdk.WINDOW_TYPE_HINT_DIALOG, + (gtk.STOCK_OK, gtk.RESPONSE_OK)) self.dialog.set_icon(TRYTON_ICON) self.dialog.set_has_separator(True) self.dialog.set_default_response(gtk.RESPONSE_OK) diff --git a/tryton/gui/window/tips.py b/tryton/gui/window/tips.py index 58ae3a3145..a5348abd3c 100644 --- a/tryton/gui/window/tips.py +++ b/tryton/gui/window/tips.py @@ -5,13 +5,14 @@ import gtk import gettext import os from tryton.config import CONFIG, TRYTON_ICON, PIXMAPS_DIR +from tryton.common import get_toplevel_window _ = gettext.gettext class Tips(object): - def __init__(self, parent): + def __init__(self): self.tips = [ _('''Welcome to Tryton @@ -41,6 +42,7 @@ You can save any graphs in PNG file with right-click on it. ] + parent = get_toplevel_window() self.win = gtk.Dialog(_('Tips'), parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) self.win.set_position(gtk.WIN_POS_CENTER_ON_PARENT) diff --git a/tryton/gui/window/view_board/action.py b/tryton/gui/window/view_board/action.py index 0c6ce475e0..12c55c8485 100644 --- a/tryton/gui/window/view_board/action.py +++ b/tryton/gui/window/view_board/action.py @@ -19,10 +19,9 @@ _ = gettext.gettext class Action(SignalEvent): - def __init__(self, window, attrs=None, context=None): + def __init__(self, attrs=None, context=None): super(Action, self).__init__() self.act_id = int(attrs['name']) - self._window = window self.screen = None self.context = context or {} @@ -30,7 +29,7 @@ class Action(SignalEvent): self.action = rpc.execute('model', 'ir.action.act_window', 'read', self.act_id, False, rpc.CONTEXT) except TrytonServerError, exception: - common.process_exception(exception, self._window) + common.process_exception(exception) raise view_ids = False @@ -147,7 +146,7 @@ class Action(SignalEvent): if self.action['res_model']: self.screen = Screen(self.action['res_model'], - self._window, mode=self.action['view_mode'], + mode=self.action['view_mode'], context=self.context, view_ids=view_ids, domain=self.domain, readonly=True, alternate_view=True) alignment.add(self.screen.screen_container.alternate_viewport) @@ -174,21 +173,21 @@ class Action(SignalEvent): ctx = {} ctx.update(rpc.CONTEXT) ctx.update(self.context) - win = WinSearch(self.action['res_model'], domain=self.domain, - context=ctx, parent=self._window) - res = win.run() - if res: - self.screen.clear() - self.screen.load(res) + def callback(result): + if result: + self.screen.clear() + self.screen.load(res) + WinSearch(self.action['res_model'], callback, domain=self.domain, + context=ctx) def _sig_open(self, widget): try: action_id = rpc.execute('model', 'ir.action', 'get_action_id', self.act_id, rpc.CONTEXT) except TrytonServerError, exception: - common.process_exception(exception, self._window) + common.process_exception(exception) if action_id: - Action2.execute(action_id, {}, self._window) + Action2.execute(action_id, {}) def _sig_previous(self, widget): self.screen.display_prev() @@ -213,7 +212,7 @@ class Action(SignalEvent): self.domain, 0, self.action['limit'] or CONFIG['client.limit'], None, rpc.CONTEXT) except TrytonServerError, exception: - common.process_exception(exception, self._window) + common.process_exception(exception) return False if self.screen: self.screen.clear() diff --git a/tryton/gui/window/view_board/parser.py b/tryton/gui/window/view_board/parser.py index cd55b045da..b69a1cbe20 100644 --- a/tryton/gui/window/view_board/parser.py +++ b/tryton/gui/window/view_board/parser.py @@ -10,8 +10,7 @@ from tryton.config import CONFIG, TRYTON_ICON class ParserBoard(object): - def __init__(self, window, context=None): - self.window = window + def __init__(self, context=None): self.title = None self.context = context @@ -176,7 +175,7 @@ class ParserBoard(object): paned.pack2(widget, resize=True, shrink=True) elif node.localName == 'action': name = str(attrs['name']) - widget_act = Action(self.window, attrs, self.context) + widget_act = Action(attrs, self.context) widgets.append(widget_act) container.wid_add(widget_act.widget, colspan=int(attrs.get('colspan', 1)), diff --git a/tryton/gui/window/view_board/view_board.py b/tryton/gui/window/view_board/view_board.py index aa26d8760e..fde66aec38 100644 --- a/tryton/gui/window/view_board/view_board.py +++ b/tryton/gui/window/view_board/view_board.py @@ -9,12 +9,11 @@ from tryton.gui.window.view_board.action import Action class ViewBoard(object): 'View board' - def __init__(self, arch, window, context=None): - self.window = window + def __init__(self, arch, context=None): self.context = context xml_dom = xml.dom.minidom.parseString(arch) - parser = ParserBoard(window, context) + parser = ParserBoard(context) for node in xml_dom.childNodes: if not node.nodeType == node.ELEMENT_NODE: continue diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index 1d5031daf9..c93715d43b 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -338,8 +338,7 @@ class M2OField(CharField): try: result = rpc.execute(*args) except TrytonServerError, exception: - result = common.process_exception(exception, record.window, - *args) + result = common.process_exception(exception, *args) if not result: return value = value, result['rec_name'] @@ -435,7 +434,7 @@ class O2MField(CharField): return from group import Group parent_name = self.attrs.get('relation_field', '') - group = Group(self.attrs['relation'], {}, record.window, + group = Group(self.attrs['relation'], {}, parent=record, parent_name=parent_name, child_name=self.name, @@ -506,7 +505,7 @@ class O2MField(CharField): elif record.model_name == self.attrs['relation']: fields = record.group.fields parent_name = self.attrs.get('relation_field', '') - group = Group(self.attrs['relation'], {}, record.window, + group = Group(self.attrs['relation'], {}, parent=record, parent_name=parent_name, child_name=self.name, context=self.context, @@ -557,13 +556,12 @@ class O2MField(CharField): try: fields_dict = rpc.execute(*args) except TrytonServerError, exception: - fields_dict = common.process_exception(exception, - record.window, *args) + fields_dict = common.process_exception(exception, *args) if not fields_dict: return False parent_name = self.attrs.get('relation_field', '') - group = Group(self.attrs['relation'], fields, record.window, + group = Group(self.attrs['relation'], fields_dict, parent=record, parent_name=parent_name, child_name=self.name, context=self.context, parent_datetime_field=self.attrs.get('datetime_field')) @@ -598,8 +596,7 @@ class O2MField(CharField): try: fields = rpc.execute(*args) except TrytonServerError, exception: - fields = common.process_exception(exception, record.window, - *args) + fields = common.process_exception(exception, *args) if not fields: return False @@ -691,7 +688,7 @@ class M2MField(O2MField): elif record.model_name == self.attrs['relation']: fields = record.group.fields parent_name = self.attrs.get('relation_field', '') - group = Group(self.attrs['relation'], {}, record.window, + group = Group(self.attrs['relation'], {}, parent=record, parent_name=parent_name, child_name=self.name, context=self.context, @@ -756,8 +753,7 @@ class ReferenceField(CharField): try: result = rpc.execute(*args) except TrytonServerError, exception: - result = common.process_exception(exception, record.window, - *args) + result = common.process_exception(exception, *args) if not result: return result = result['rec_name'] diff --git a/tryton/gui/window/view_form/model/group.py b/tryton/gui/window/view_form/model/group.py index 10ae5f0d01..ec6c5731b3 100644 --- a/tryton/gui/window/view_form/model/group.py +++ b/tryton/gui/window/view_form/model/group.py @@ -12,7 +12,7 @@ from tryton.common.domain_inversion import is_leaf class Group(SignalEvent, list): - def __init__(self, model_name, fields, window, ids=None, parent=None, + def __init__(self, model_name, fields, ids=None, parent=None, parent_name='', child_name='', context=None, domain=None, readonly=False, parent_datetime_field=None): super(Group, self).__init__() @@ -21,7 +21,6 @@ class Group(SignalEvent, list): self.__domain = domain self.__domain4inversion = None self.lock_signal = False - self.__window = window self.parent = parent self.parent_name = parent_name or '' self.child_name = child_name @@ -41,16 +40,6 @@ class Group(SignalEvent, list): self.__field_childs = None self.exclude_field = None - def __get_window(self): - return self.__window - - def __set_window(self, window): - for record in self: - record.window = window - self.__window = window - - window = property(__get_window, __set_window) - @property def domain(self): if self.parent and self.child_name: @@ -194,7 +183,7 @@ class Group(SignalEvent, list): try: res += rpc.execute(*args) except TrytonServerError, exception: - res2 = common.process_exception(exception, self.window, *args) + res2 = common.process_exception(exception, *args) if not res2: return False res += res2 @@ -211,8 +200,7 @@ class Group(SignalEvent, list): for id in ids: if self.get(id): continue - new_record = Record(self.model_name, id, self.window, - group=self) + new_record = Record(self.model_name, id, group=self) self.append(new_record) new_records.append(new_record) new_record.signal_connect(self, 'record-changed', @@ -255,7 +243,6 @@ class Group(SignalEvent, list): if record.group is not self: record.signal_unconnect(record.group) record.group = self - record.window = self.window record.signal_connect(self, 'record-changed', self._record_changed) record.signal_connect(self, 'record-modified', self._record_modified) if position == -1: @@ -287,7 +274,7 @@ class Group(SignalEvent, list): def new(self, default=True, domain=None, context=None, signal=True, obj_id=None): - record = Record(self.model_name, obj_id, self.window, group=self) + record = Record(self.model_name, obj_id, group=self) record.signal_connect(self, 'record-changed', self._record_changed) record.signal_connect(self, 'record-modified', self._record_modified) if default: @@ -387,7 +374,7 @@ class Group(SignalEvent, list): try: values = rpc.execute(*args) except TrytonServerError, exception: - values = common.process_exception(exception, self.window, *args) + values = common.process_exception(exception, *args) if not values: return False for name in to_add: @@ -408,7 +395,6 @@ class Group(SignalEvent, list): def destroy(self): super(Group, self).destroy() - self.__window = None self.parent = None self.fields = {} self.record_deleted, self.record_removed = [], [] diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py index ec86e07939..949a2ad3ad 100644 --- a/tryton/gui/window/view_form/model/record.py +++ b/tryton/gui/window/view_form/model/record.py @@ -16,9 +16,8 @@ class Record(SignalEvent): id = -1 - def __init__(self, model_name, obj_id, window, group=None): + def __init__(self, model_name, obj_id, group=None): super(Record, self).__init__() - self.__window = window self.model_name = model_name self.id = obj_id or Record.id if self.id < 0: @@ -79,7 +78,7 @@ class Record(SignalEvent): except TrytonServerError, exception: if raise_exception: raise - values = common.process_exception(exception, self.window, *args) + values = common.process_exception(exception, *args) if not values: values = [{'id': x} for x in ids] id2value = dict((value['id'], value) for value in values) @@ -129,8 +128,6 @@ class Record(SignalEvent): group.on_write = self.group.on_write group.readonly = self.group.readonly group._context.update(self.group._context) - if group.window != self.window: - group.window = self.window return group def get_path(self, group): @@ -146,19 +143,6 @@ class Record(SignalEvent): path.reverse() return tuple(path) - def _get_window(self): - return self.__window - - def _set_window(self, window): - self.__window = window - for fieldname, value in self.value.iteritems(): - if fieldname not in self.group.fields: - continue - if isinstance(self.group.fields[fieldname], field.O2MField): - value.window = window - - window = property(_get_window, _set_window) - def get_removed(self): if self.group is not None: return self in self.group.record_removed @@ -248,8 +232,7 @@ class Record(SignalEvent): try: res = rpc.execute(*args) except TrytonServerError, exception: - res = common.process_exception(exception, self.window, - *args) + res = common.process_exception(exception, *args) if not res: return False old_id = self.id @@ -269,8 +252,7 @@ class Record(SignalEvent): if not rpc.execute(*args): return False except TrytonServerError, exception: - res = common.process_exception(exception, self.window, - *args) + res = common.process_exception(exception, *args) if not res: return False self._loaded.clear() @@ -291,7 +273,7 @@ class Record(SignalEvent): try: vals = rpc.execute(*args) except TrytonServerError, exception: - vals = common.process_exception(exception, self.window, *args) + vals = common.process_exception(exception, *args) if not vals: return if (self.parent @@ -312,7 +294,7 @@ class Record(SignalEvent): try: res = rpc.execute(*args) except TrytonServerError, exception: - res = common.process_exception(exception, self.window, *args) + res = common.process_exception(exception, *args) if not res: return '' return res['rec_name'] @@ -464,7 +446,7 @@ class Record(SignalEvent): try: res = rpc.execute(*args) except TrytonServerError, exception: - res = common.process_exception(exception, self.window, *args) + res = common.process_exception(exception, *args) if not res: return later = {} @@ -514,7 +496,7 @@ class Record(SignalEvent): try: res = rpc.execute(*args) except TrytonServerError, exception: - res = common.process_exception(exception, self.window, *args) + res = common.process_exception(exception, *args) if not res: return self.group.fields[fieldname].set_on_change(self, res) @@ -537,7 +519,7 @@ class Record(SignalEvent): try: res = rpc.execute(*args) except TrytonServerError, exception: - res = common.process_exception(exception, self.window, *args) + res = common.process_exception(exception, *args) if not res: # ensure res is a list res = [] @@ -551,7 +533,7 @@ class Record(SignalEvent): try: res = rpc.execute(*args) except TrytonServerError, exception: - res = common.process_exception(exception, self.window, *args) + res = common.process_exception(exception, *args) if not res: return self.set_default(res) @@ -571,7 +553,6 @@ class Record(SignalEvent): def destroy(self): super(Record, self).destroy() - self.window = None self.group = None self.value = None self.next = None diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py index 96ca669f0a..85dd9c3ade 100644 --- a/tryton/gui/window/view_form/screen/screen.py +++ b/tryton/gui/window/view_form/screen/screen.py @@ -18,10 +18,10 @@ from tryton.exceptions import TrytonServerError class Screen(SignalEvent): "Screen" - def __init__(self, model_name, window, view_ids=None, mode=None, - context=None, views_preload=None, domain=None, row_activate=None, - limit=None, readonly=False, exclude_field=None, sort=None, - search_value=None, alternate_view=False): + def __init__(self, model_name, view_ids=None, mode=None, context=None, + views_preload=None, domain=None, row_activate=None, limit=None, + readonly=False, exclude_field=None, sort=None, search_value=None, + alternate_view=False): if view_ids is None: view_ids = [] if mode is None: @@ -50,7 +50,6 @@ class Screen(SignalEvent): self.parent = None self.parent_name = None self.exclude_field = exclude_field - self.__window = window self.filter_widget = None self.__group = None self.new_group() @@ -92,8 +91,8 @@ class Screen(SignalEvent): except TrytonServerError: return self.filter_widget = Form(self.fields_view_tree, - self.model_name, self.window, self.domain, - (self, self.search_filter), self.context) + self.model_name, self.domain, (self, self.search_filter), + self.context) self.screen_container.add_filter(self.filter_widget.widget, self.search_filter, self.search_clear, self.search_prev, self.search_next) @@ -138,8 +137,7 @@ class Screen(SignalEvent): try: ids = rpc.execute(*rpc_args) except TrytonServerError, exception: - ids = (common.process_exception(exception, self.window, *rpc_args) - or []) + ids = (common.process_exception(exception, *rpc_args) or []) if not only_ids: if len(ids) == limit: rpc_args = ('model', self.model_name, 'search_count', values, @@ -148,7 +146,7 @@ class Screen(SignalEvent): self.search_count = rpc.execute(*rpc_args) except TrytonServerError, exception: self.search_count = (common.process_exception(exception, - self.window, *rpc_args) or 0) + *rpc_args) or 0) else: self.search_count = len(ids) self.screen_container.but_prev.set_sensitive(bool(offset)) @@ -193,7 +191,7 @@ class Screen(SignalEvent): group = property(__get_group, __set_group) def new_group(self): - self.group = Group(self.model_name, {}, self.window, domain=self.domain, + self.group = Group(self.model_name, {}, domain=self.domain, context=self.context, readonly=self.readonly) def _group_cleared(self, group, signal): @@ -243,15 +241,6 @@ class Screen(SignalEvent): current_record = property(__get_current_record, __set_current_record) - def __get_window(self): - return self.__window - - def __set_window(self, window): - self.group.window = window - self.__window = window - - window = property(__get_window, __set_window) - def update_attachment(self, record): if record != self.current_record: return False @@ -266,7 +255,6 @@ class Screen(SignalEvent): self.group.signal_unconnect(self) self.group.destroy() self.parent = None - self.__window = None self.__group = None self.__current_record = None self.screen_container = None @@ -274,9 +262,16 @@ class Screen(SignalEvent): def default_row_activate(self): from tryton.action import Action + from tryton.gui.main import Main + main = Main.get_main() + current_form = main.get_page() + if current_form: + for dialog in current_form.dialogs: + dialog.hide() + if (self.current_view.view_type == 'tree' and self.current_view.widget_tree.keyword_open): - return Action.exec_keyword('tree_open', self.window, { + return Action.exec_keyword('tree_open', { 'model': self.model_name, 'id': self.id_get(), 'ids': [self.id_get()], @@ -338,7 +333,7 @@ class Screen(SignalEvent): try: view = rpc.execute(*args) except TrytonServerError, exception: - view = common.process_exception(exception, self.window, *args) + view = common.process_exception(exception, *args) if not view: return return self.add_view(view, display, context=context) @@ -366,7 +361,7 @@ class Screen(SignalEvent): from tryton.gui.window.view_form.view.widget_parse import WidgetParse self.group.add_fields(fields, context=context) - parser = WidgetParse(parent=self.parent, window=self.window) + parser = WidgetParse(parent=self.parent) view = parser.parse(self, xml_dom, self.group.fields, children_field=children_field) @@ -537,8 +532,7 @@ class Screen(SignalEvent): try: res = rpc.execute(*args) except TrytonServerError, exception: - res = common.process_exception(exception, self.window, - *args) + res = common.process_exception(exception, *args) if not res: return False self.current_view.set_cursor() @@ -583,8 +577,7 @@ class Screen(SignalEvent): try: res = rpc.execute(*args) except TrytonServerError, exception: - res = common.process_exception(exception, self.window, - *args) + res = common.process_exception(exception, *args) if not res: return False if not records: diff --git a/tryton/gui/window/view_form/view/form.py b/tryton/gui/window/view_form/view/form.py index 28efec28f1..6e05a63af8 100644 --- a/tryton/gui/window/view_form/view/form.py +++ b/tryton/gui/window/view_form/view/form.py @@ -15,11 +15,10 @@ _ = gettext.gettext class ViewForm(ParserView): - def __init__(self, window, screen, widget, children=None, - buttons=None, notebooks=None, cursor_widget='', - children_field=None): - super(ViewForm, self).__init__(window, screen, widget, children, - buttons, notebooks, cursor_widget, children_field) + def __init__(self, screen, widget, children=None, buttons=None, + notebooks=None, cursor_widget='', children_field=None): + super(ViewForm, self).__init__(screen, widget, children, buttons, + notebooks, cursor_widget, children_field) self.view_type = 'form' for button in self.buttons: @@ -41,15 +40,6 @@ class ViewForm(ParserView): viewport = gtk.Viewport() viewport.set_shadow_type(gtk.SHADOW_ETCHED_IN) viewport.add(scroll) - if isinstance(self.screen.window, gtk.Dialog): - width, height = self.widget.size_request() - if self.screen.window: - parent = self.screen.window.get_transient_for() - if parent: - parent_width, parent_height = parent.get_size() - width = min(parent_width - 40, width) - height = min(parent_height - 80, height) - vbox.set_size_request(width or -1, height or -1) vbox.pack_start(viewport, expand=True, fill=True) self.widget = vbox diff --git a/tryton/gui/window/view_form/view/form_gtk/binary.py b/tryton/gui/window/view_form/view/form_gtk/binary.py index 26c376e31f..ba5335e772 100644 --- a/tryton/gui/window/view_form/view/form_gtk/binary.py +++ b/tryton/gui/window/view_form/view/form_gtk/binary.py @@ -20,9 +20,8 @@ def humanize(size): class Binary(WidgetInterface): "Binary" - def __init__(self, field_name, model_name, window, attrs=None): - super(Binary, self).__init__(field_name, model_name, window, - attrs=attrs) + def __init__(self, field_name, model_name, attrs=None): + super(Binary, self).__init__(field_name, model_name, attrs=attrs) self.filename = attrs.get('filename') @@ -136,7 +135,7 @@ class Binary(WidgetInterface): root, type_ = os.path.splitext(filename) if type_: type_ = type_[1:] - file_open(file_path, type_, self.window) + file_open(file_path, type_) def sig_save_as(self, widget=None): filename = '' diff --git a/tryton/gui/window/view_form/view/form_gtk/calendar.py b/tryton/gui/window/view_form/view/form_gtk/calendar.py index 7b1ac1be87..f769657ce9 100644 --- a/tryton/gui/window/view_form/view/form_gtk/calendar.py +++ b/tryton/gui/window/view_form/view/form_gtk/calendar.py @@ -9,7 +9,8 @@ from interface import WidgetInterface import tryton.rpc as rpc from tryton.common import DT_FORMAT, DHM_FORMAT, HM_FORMAT, message, \ TRYTON_ICON, timezoned_date -from tryton.common import date_widget, Tooltips, datetime_strftime +from tryton.common import date_widget, Tooltips, datetime_strftime, \ + get_toplevel_window from tryton.translate import date_format _ = gettext.gettext @@ -18,9 +19,8 @@ _ = gettext.gettext class Calendar(WidgetInterface): "Calendar" - def __init__(self, field_name, model_name, window, attrs=None): - super(Calendar, self).__init__(field_name, model_name, window, - attrs=attrs) + def __init__(self, field_name, model_name, attrs=None): + super(Calendar, self).__init__(field_name, model_name, attrs=attrs) self.format = date_format() self.widget = date_widget.ComplexEntry(self.format, spacing=0) @@ -106,7 +106,8 @@ class Calendar(WidgetInterface): return True def cal_open(self, widget): - win = gtk.Dialog(_('Date Selection'), self.window, + parent = get_toplevel_window() + win = gtk.Dialog(_('Date Selection'), parent, gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)) @@ -144,16 +145,15 @@ class Calendar(WidgetInterface): format = format.replace('%Y', '0%Y') self.entry.set_text(datetime_strftime(date, format)) self._focus_out() - self.window.present() + parent.present() win.destroy() class DateTime(WidgetInterface): "DateTime" - def __init__(self, field_name, model_name, window, attrs=None): - super(DateTime, self).__init__(field_name, model_name, window, - attrs=attrs) + def __init__(self, field_name, model_name, attrs=None): + super(DateTime, self).__init__(field_name, model_name, attrs=attrs) self.format = date_format() + ' ' + HM_FORMAT self.widget = date_widget.ComplexEntry(self.format, spacing=0) @@ -239,7 +239,8 @@ class DateTime(WidgetInterface): return True def cal_open(self, widget): - win = gtk.Dialog(_('Date Time Selection'), self.window, + parent = get_toplevel_window() + win = gtk.Dialog(_('Date Time Selection'), parent, gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)) @@ -290,5 +291,5 @@ class DateTime(WidgetInterface): value = datetime_strftime(date, DHM_FORMAT) self.show(value, timezone=False) self._focus_out() - self.window.present() + parent.present() win.destroy() diff --git a/tryton/gui/window/view_form/view/form_gtk/char.py b/tryton/gui/window/view_form/view/form_gtk/char.py index 5913d71911..b4e96083a8 100644 --- a/tryton/gui/window/view_form/view/form_gtk/char.py +++ b/tryton/gui/window/view_form/view/form_gtk/char.py @@ -13,8 +13,8 @@ _ = gettext.gettext class Char(WidgetInterface): "Char" - def __init__(self, field_name, model_name, window, attrs=None): - super(Char, self).__init__(field_name, model_name, window, attrs=attrs) + def __init__(self, field_name, model_name, attrs=None): + super(Char, self).__init__(field_name, model_name, attrs=attrs) self.widget = gtk.HBox() self.autocomplete = bool(attrs.get('autocomplete')) @@ -95,8 +95,8 @@ class Char(WidgetInterface): class Sha(Char): - def __init__(self, field_name, model_name, window, attrs=None): - super(Sha, self).__init__(field_name, model_name, window, attrs=attrs) + def __init__(self, field_name, model_name, attrs=None): + super(Sha, self).__init__(field_name, model_name, attrs=attrs) self.entry.props.visibility = False self.visibility_checkbox = gtk.CheckButton() diff --git a/tryton/gui/window/view_form/view/form_gtk/checkbox.py b/tryton/gui/window/view_form/view/form_gtk/checkbox.py index af53de82ac..1bdca3f739 100644 --- a/tryton/gui/window/view_form/view/form_gtk/checkbox.py +++ b/tryton/gui/window/view_form/view/form_gtk/checkbox.py @@ -8,9 +8,8 @@ _ = gettext.gettext class CheckBox(WidgetInterface): - def __init__(self, field_name, model_name, window, attrs=None): - super(CheckBox, self).__init__(field_name, model_name, window, - attrs=attrs) + def __init__(self, field_name, model_name, attrs=None): + super(CheckBox, self).__init__(field_name, model_name, attrs=attrs) self.widget = gtk.CheckButton() self.widget.connect('focus-in-event', lambda x, y: self._focus_in()) self.widget.connect('focus-out-event', lambda x, y: self._focus_out()) diff --git a/tryton/gui/window/view_form/view/form_gtk/float.py b/tryton/gui/window/view_form/view/form_gtk/float.py index 7a3537171b..3f2962619f 100644 --- a/tryton/gui/window/view_form/view/form_gtk/float.py +++ b/tryton/gui/window/view_form/view/form_gtk/float.py @@ -8,9 +8,8 @@ from integer import Integer class Float(Integer): "Float" - def __init__(self, field_name, model_name, window, attrs=None): - super(Float, self).__init__(field_name, model_name, window, - attrs=attrs) + def __init__(self, field_name, model_name, attrs=None): + super(Float, self).__init__(field_name, model_name, attrs=attrs) self.digits = (16, 2) self.entry.connect('key-press-event', self.key_press_event) diff --git a/tryton/gui/window/view_form/view/form_gtk/float_time.py b/tryton/gui/window/view_form/view/form_gtk/float_time.py index cefbec4c89..1644babecf 100644 --- a/tryton/gui/window/view_form/view/form_gtk/float_time.py +++ b/tryton/gui/window/view_form/view/form_gtk/float_time.py @@ -8,9 +8,8 @@ import tryton.rpc as rpc class FloatTime(WidgetInterface): - def __init__(self, field_name, model_name, window, attrs=None): - super(FloatTime, self).__init__(field_name, model_name, window, - attrs=attrs) + def __init__(self, field_name, model_name, attrs=None): + super(FloatTime, self).__init__(field_name, model_name, attrs=attrs) self.widget = gtk.HBox() self.entry = gtk.Entry() diff --git a/tryton/gui/window/view_form/view/form_gtk/image.py b/tryton/gui/window/view_form/view/form_gtk/image.py index 17d9164b02..61ca8fcf50 100644 --- a/tryton/gui/window/view_form/view/form_gtk/image.py +++ b/tryton/gui/window/view_form/view/form_gtk/image.py @@ -18,9 +18,8 @@ NOIMAGE = open(os.path.join(PIXMAPS_DIR, 'tryton-noimage.png'), 'rb').read() class Image(WidgetInterface): - def __init__(self, field_name, model_name, window, attrs=None): - super(Image, self).__init__(field_name, model_name, window, - attrs=attrs) + def __init__(self, field_name, model_name, attrs=None): + super(Image, self).__init__(field_name, model_name, attrs=attrs) self.filename = attrs.get('filename') self.height = int(attrs.get('img_height', 100)) @@ -127,8 +126,8 @@ class Image(WidgetInterface): for pat in ("*.png", "*.jpg", "*.gif", "*.tif", "*.xpm"): filter_image.add_pattern(pat) - filename = file_selection(_('Open...'), parent=self.window, - preview=True, filters=[filter_image, filter_all]) + filename = file_selection(_('Open...'), preview=True, + filters=[filter_image, filter_all]) if filename: self.field.set_client(self.record, encodestring(open(filename, 'rb').read())) @@ -149,14 +148,14 @@ class Image(WidgetInterface): root, type_ = os.path.splitext(filename) if type_: type_ = type_[1:] - file_open(file_path, type_, self.window) + file_open(file_path, type_) def sig_save_as(self, widget): filename = '' if self.filename_field: filename = self.filename_field.get(self.record) filename = file_selection(_('Save As...'), filename=filename, - parent=self.window, action=gtk.FILE_CHOOSER_ACTION_SAVE) + action=gtk.FILE_CHOOSER_ACTION_SAVE) if filename: with open(filename, 'wb') as fp: fp.write(decodestring(self.field.get(self.record))) diff --git a/tryton/gui/window/view_form/view/form_gtk/integer.py b/tryton/gui/window/view_form/view/form_gtk/integer.py index 1600b6c876..73cf0452dc 100644 --- a/tryton/gui/window/view_form/view/form_gtk/integer.py +++ b/tryton/gui/window/view_form/view/form_gtk/integer.py @@ -7,9 +7,8 @@ import locale class Integer(Char): "Integer" - def __init__(self, field_name, model_name, window, attrs=None): - super(Integer, self).__init__(field_name, model_name, window, - attrs=attrs) + def __init__(self, field_name, model_name, attrs=None): + super(Integer, self).__init__(field_name, model_name, attrs=attrs) self.entry.set_max_length(0) self.entry.set_alignment(1.0) self.entry.connect('insert_text', self.sig_insert_text) diff --git a/tryton/gui/window/view_form/view/form_gtk/interface.py b/tryton/gui/window/view_form/view/form_gtk/interface.py index ac52d4f52b..9010889807 100644 --- a/tryton/gui/window/view_form/view/form_gtk/interface.py +++ b/tryton/gui/window/view_form/view/form_gtk/interface.py @@ -6,10 +6,9 @@ from tryton.common import COLORS class WidgetInterface(object): - def __init__(self, field_name, model_name, window, attrs=None): + def __init__(self, field_name, model_name, attrs=None): self.field_name = field_name self.model_name = model_name - self.window = window self.view = None # Filled by ViewForm self.attrs = attrs or {} for attr_name in ('readonly', 'invisible'): diff --git a/tryton/gui/window/view_form/view/form_gtk/many2many.py b/tryton/gui/window/view_form/view/form_gtk/many2many.py index 8720c42ba5..cddc7af756 100644 --- a/tryton/gui/window/view_form/view/form_gtk/many2many.py +++ b/tryton/gui/window/view_form/view/form_gtk/many2many.py @@ -16,9 +16,8 @@ _ = gettext.gettext class Many2Many(WidgetInterface): - def __init__(self, field_name, model_name, window, attrs=None): - super(Many2Many, self).__init__(field_name, model_name, window, - attrs=attrs) + def __init__(self, field_name, model_name, attrs=None): + super(Many2Many, self).__init__(field_name, model_name, attrs=attrs) self.widget = gtk.VBox(homogeneous=False, spacing=5) self._readonly = True @@ -71,13 +70,11 @@ class Many2Many(WidgetInterface): frame.set_shadow_type(gtk.SHADOW_OUT) self.widget.pack_start(frame, expand=False, fill=True) - self.screen = Screen(attrs['relation'], self.window, - mode=['tree'], views_preload=attrs.get('views', {}), - row_activate=self._on_activate) + self.screen = Screen(attrs['relation'], mode=['tree'], + views_preload=attrs.get('views', {}), + row_activate=self._on_activate) self.screen.signal_connect(self, 'record-message', self._sig_label) - if not isinstance(self.screen.window, gtk.Dialog): - self.screen.widget.set_size_request(0, 0) self.widget.pack_start(self.screen.widget, expand=True, fill=True) self.screen.widget.connect('key_press_event', self.on_keypress) @@ -130,23 +127,24 @@ class Many2Many(WidgetInterface): ids = rpc.execute('model', self.attrs['relation'], 'search', dom , 0, CONFIG['client.limit'], None, context) except TrytonServerError, exception: - common.process_exception(exception, self.window) + common.process_exception(exception) return False - if len(ids) != 1 or not value: - win = WinSearch(self.attrs['relation'], sel_multi=True, ids=ids, - context=context, domain=domain, - parent=self.widget.get_toplevel(), - views_preload=self.attrs.get('views', {})) - ids = win.run() - res_id = None - if ids: - res_id = ids[0] - self.screen.load(ids, modified=True) - self.screen.display(res_id=res_id) - if self.screen.current_view: - self.screen.current_view.set_cursor() - self.wid_text.set_text('') + def callback(ids): + res_id = None + if ids: + res_id = ids[0] + self.screen.load(ids, modified=True) + self.screen.display(res_id=res_id) + if self.screen.current_view: + self.screen.current_view.set_cursor() + self.wid_text.set_text('') + if len(ids) != 1 or not value: + WinSearch(self.attrs['relation'], callback, sel_multi=True, + ids=ids, context=context, domain=domain, + views_preload=self.attrs.get('views', {})) + else: + callback(ids) def _sig_remove(self, *args): self.screen.remove(remove=True) @@ -160,12 +158,12 @@ class Many2Many(WidgetInterface): def _sig_edit(self): if self.screen.current_record: - win = WinForm(self.screen, self.widget.get_toplevel()) - if win.run(): - self.screen.current_record.save() - else: - self.screen.current_record.cancel() - win.destroy() + def callback(result): + if result: + self.screen.current_record.save() + else: + self.screen.current_record.cancel() + WinForm(self.screen, callback) def _readonly_set(self, value): self._readonly = value diff --git a/tryton/gui/window/view_form/view/form_gtk/many2one.py b/tryton/gui/window/view_form/view/form_gtk/many2one.py index d6d635ac7e..8355e29582 100644 --- a/tryton/gui/window/view_form/view/form_gtk/many2one.py +++ b/tryton/gui/window/view_form/view/form_gtk/many2one.py @@ -21,9 +21,8 @@ _ = gettext.gettext class Many2One(WidgetInterface): - def __init__(self, field_name, model_name, window, attrs=None): - super(Many2One, self).__init__(field_name, model_name, window, - attrs=attrs) + def __init__(self, field_name, model_name, attrs=None): + super(Many2One, self).__init__(field_name, model_name, attrs=attrs) self.widget = gtk.HBox(spacing=0) self.widget.set_property('sensitive', True) @@ -116,55 +115,48 @@ class Many2One(WidgetInterface): context) except TrytonServerError, exception: self.focus_out = True - common.process_exception(exception, self.window) + common.process_exception(exception) self.changed = True - return False + return if len(ids)==1: self.field.set_client(self.record, ids[0], force_change=True) self.focus_out = True self.display(self.record, self.field) - return True + return + def callback(ids): + if ids: + self.field.set_client(self.record, ids[0], + force_change=True) + self.focus_out = True + self.display(self.record, self.field) - win = WinSearch(self.attrs['relation'], sel_multi=False, - ids=ids, context=context, domain=domain, - parent=self.widget.get_toplevel(), - views_preload=self.attrs.get('views', {})) - ids = win.run() - if ids: - self.field.set_client(self.record, ids[0], - force_change=True) - self.focus_out = True - self.display(self.record, self.field) - return True - else: - self.focus_out = True - self.display(self.record, self.field) - return False + WinSearch(self.attrs['relation'], callback, sel_multi=False, + ids=ids, context=context, domain=domain, + views_preload=self.attrs.get('views', {})) + return self.focus_out = True self.display(self.record, self.field) self.changed = True - return True + return def get_screen(self): domain = self.field.domain_get(self.record) context = self.field.context_get(self.record) - return Screen(self.attrs['relation'], self.window, domain=domain, - context=context, mode=['form'], - views_preload=self.attrs.get('views', {}), - readonly=self._readonly) + return Screen(self.attrs['relation'], domain=domain, context=context, + mode=['form'], views_preload=self.attrs.get('views', {}), + readonly=self._readonly) def sig_new(self, *args): self.focus_out = False screen = self.get_screen() - win = WinForm(screen, self.widget.get_toplevel(), new=True) - if win.run(): - if screen.save_current(): + def callback(result): + if result and screen.save_current(): value = (screen.current_record.id, screen.current_record.rec_name()) self.field.set_client(self.record, value) - win.destroy() - self.focus_out = True + self.focus_out = True + WinForm(screen, callback, new=True) def sig_edit(self, widget): self.changed = False @@ -173,53 +165,59 @@ class Many2One(WidgetInterface): if value: screen = self.get_screen() screen.load([self.field.get(self.record)]) - win = WinForm(screen, self.widget.get_toplevel()) - while win.run(): - if screen.save_current(): + def callback(result): + if result and screen.save_current(): value = (screen.current_record.id, screen.current_record.rec_name()) - self.field.set_client(self.record, value, force_change=True) - break - else: + self.field.set_client(self.record, value, + force_change=True) + elif result: screen.display() - win.destroy() - else: - if not self._readonly: - domain = self.field.domain_get(self.record) - context = rpc.CONTEXT.copy() - context.update(self.field.context_get(self.record)) - self.wid_text.grab_focus() + return WinForm(screen, callback) + self.focus_out = True + self.display(self.record, self.field) + self.changed = True + WinForm(screen, callback) + return + elif not self._readonly: + domain = self.field.domain_get(self.record) + context = rpc.CONTEXT.copy() + context.update(self.field.context_get(self.record)) + self.wid_text.grab_focus() - try: - if self.wid_text.get_text(): - dom = [('rec_name', 'ilike', - '%' + self.wid_text.get_text() + '%'), - domain] - else: - dom = domain - ids = rpc.execute('model', self.attrs['relation'], - 'search', dom, 0, CONFIG['client.limit'], None, - context) - except TrytonServerError, exception: - self.focus_out = True - common.process_exception(exception, self.window) - self.changed = True - return False - if ids and len(ids)==1: - self.field.set_client(self.record, ids[0], - force_change=True) - self.focus_out = True - self.display(self.record, self.field) - return True + try: + if self.wid_text.get_text(): + dom = [('rec_name', 'ilike', + '%' + self.wid_text.get_text() + '%'), + domain] + else: + dom = domain + ids = rpc.execute('model', self.attrs['relation'], + 'search', dom, 0, CONFIG['client.limit'], None, + context) + except TrytonServerError, exception: + self.focus_out = True + common.process_exception(exception) + self.changed = True + return False + if ids and len(ids)==1: + self.field.set_client(self.record, ids[0], + force_change=True) + self.focus_out = True + self.display(self.record, self.field) + return True - win = WinSearch(self.attrs['relation'], sel_multi=False, - ids=ids, context=context, - domain=domain, parent=self.widget.get_toplevel(), - views_preload=self.attrs.get('views', {})) - ids = win.run() + def callback(ids): if ids: self.field.set_client(self.record, ids[0], force_change=True) + self.focus_out = True + self.display(self.record, self.field) + self.changed = True + WinSearch(self.attrs['relation'], callback, sel_multi=False, + ids=ids, context=context, domain=domain, + views_preload=self.attrs.get('views', {})) + return self.focus_out = True self.display(self.record, self.field) self.changed = True @@ -233,7 +231,7 @@ class Many2One(WidgetInterface): self.sig_edit(widget) return True elif event.keyval in (gtk.keysyms.Tab, gtk.keysyms.Return) and editable: - return not self.sig_activate(widget, event, key_press=True) + self.sig_activate(widget, event, key_press=True) return False def sig_changed(self, *args): @@ -273,7 +271,7 @@ class Many2One(WidgetInterface): try: relates = rpc.execute(*args) except TrytonServerError, exception: - relates = common.process_exception(exception, self.window) + relates = common.process_exception(exception) if not relates: return False menu_entries = [] @@ -308,10 +306,9 @@ class Many2One(WidgetInterface): act = action.copy() obj_id = self.field.get(self.record) if not obj_id: - common.message(_('You must select a record to use the relation!'), - self.window) + common.message(_('You must select a record to use the relation!')) return False - screen = Screen(self.attrs['relation'], self.window) + screen = Screen(self.attrs['relation']) screen.load([obj_id]) encoder = PYSONEncoder() act['domain'] = encoder.encode(screen.current_record.expr_eval( @@ -321,11 +318,11 @@ class Many2One(WidgetInterface): data['model'] = self.attrs['relation'] data['id'] = obj_id data['ids'] = [obj_id] - return Action._exec_action(act, self.window, data, context) + return Action._exec_action(act, data, context) def click_and_action(self, atype): obj_id = self.field.get(self.record) - return Action.exec_keyword(atype, self.window, { + return Action.exec_keyword(atype, { 'model': self.attrs['relation'], 'id': obj_id or False, 'ids': [obj_id], diff --git a/tryton/gui/window/view_form/view/form_gtk/one2many.py b/tryton/gui/window/view_form/view/form_gtk/one2many.py index e3e6114ac0..ef204a4f6f 100644 --- a/tryton/gui/window/view_form/view/form_gtk/one2many.py +++ b/tryton/gui/window/view_form/view/form_gtk/one2many.py @@ -18,9 +18,8 @@ _ = gettext.gettext class One2Many(WidgetInterface): - def __init__(self, field_name, model_name, window, attrs=None): - super(One2Many, self).__init__(field_name, model_name, window, - attrs=attrs) + def __init__(self, field_name, model_name, attrs=None): + super(One2Many, self).__init__(field_name, model_name, attrs=attrs) self.widget = gtk.VBox(homogeneous=False, spacing=2) self._readonly = True @@ -154,15 +153,13 @@ class One2Many(WidgetInterface): frame.set_shadow_type(gtk.SHADOW_OUT) self.widget.pack_start(frame, expand=False, fill=True) - self.screen = Screen(attrs['relation'], self.window, - mode=attrs.get('mode', 'tree,form').split(','), - views_preload=attrs.get('views', {}), - row_activate=self._on_activate, - exclude_field=attrs.get('relation_field', None)) + self.screen = Screen(attrs['relation'], + mode=attrs.get('mode', 'tree,form').split(','), + views_preload=attrs.get('views', {}), + row_activate=self._on_activate, + exclude_field=attrs.get('relation_field', None)) self.screen.signal_connect(self, 'record-message', self._sig_label) - if not isinstance(self.screen.window, gtk.Dialog): - self.screen.widget.set_size_request(0, 0) self.widget.pack_start(self.screen.widget, expand=True, fill=True) self.screen.widget.connect('key_press_event', self.on_keypress) @@ -236,17 +233,19 @@ class One2Many(WidgetInterface): sequence = None if self.screen.current_view.view_type == 'tree': sequence = self.screen.current_view.widget_tree.sequence + + def update_sequence(): + if sequence: + self.screen.group.set_sequence(field=sequence) + if (self.screen.current_view.view_type == 'form') \ or self.screen.editable_get(): self.screen.new(context=ctx) self.screen.current_view.widget.set_sensitive(True) + update_sequence() else: - win = WinForm(self.screen, self.widget.get_toplevel(), new=True, + WinForm(self.screen, lambda a: update_sequence(), new=True, many=True, context=ctx) - win.run() - win.destroy() - if sequence: - self.screen.group.set_sequence(field=sequence) def _sig_edit(self, widget=None): self.view.set_value() @@ -256,9 +255,7 @@ class One2Many(WidgetInterface): if not record.validate(fields): self.screen.display() return - win = WinForm(self.screen, self.widget.get_toplevel()) - win.run() - win.destroy() + WinForm(self.screen, lambda a: None) def _sig_next(self, widget): self.view.set_value() @@ -309,22 +306,24 @@ class One2Many(WidgetInterface): ids = rpc.execute('model', self.attrs['relation'], 'search', dom, 0, CONFIG['client.limit'], None, context) except TrytonServerError, exception: - common.process_exception(exception, self.window) + common.process_exception(exception) return False + def callback(ids): + res_id = None + if ids: + res_id = ids[0] + self.screen.load(ids, modified=True) + self.screen.display(res_id=res_id) + if self.screen.current_view: + self.screen.current_view.set_cursor() + self.wid_text.set_text('') if len(ids) != 1: - win = WinSearch(self.attrs['relation'], sel_multi=True, ids=ids, - context=context, domain=domain, parent=self.window, - views_preload=self.attrs.get('views', {})) - ids = win.run() + WinSearch(self.attrs['relation'], callback, sel_multi=True, + ids=ids, context=context, domain=domain, + views_preload=self.attrs.get('views', {})) + else: + callback(ids) - res_id = None - if ids: - res_id = ids[0] - self.screen.load(ids, modified=True) - self.screen.display(res_id=res_id) - if self.screen.current_view: - self.screen.current_view.set_cursor() - self.wid_text.set_text('') def _sig_label(self, screen, signal_data): name = '_' diff --git a/tryton/gui/window/view_form/view/form_gtk/parser.py b/tryton/gui/window/view_form/view/form_gtk/parser.py index f9c5d028e3..90205588c4 100644 --- a/tryton/gui/window/view_form/view/form_gtk/parser.py +++ b/tryton/gui/window/view_form/view/form_gtk/parser.py @@ -46,7 +46,7 @@ class Button(object): obj_id = self.form.screen.save_current() if obj_id: if not self.attrs.get('confirm', False) or \ - common.sur(self.attrs['confirm'], self.form.window): + common.sur(self.attrs['confirm']): button_type = self.attrs.get('type', 'workflow') ctx = rpc.CONTEXT.copy() ctx.update(record.context_get()) @@ -57,16 +57,14 @@ class Button(object): try: rpc.execute(*args) except TrytonServerError, exception: - common.process_exception(exception, self.form.window, - *args) + common.process_exception(exception, *args) elif button_type == 'object': args = ('model', self.form.screen.model_name, self.attrs['name'], [obj_id], ctx) try: rpc.execute(*args) except TrytonServerError, exception: - common.process_exception(exception, self.form.window, - *args) + common.process_exception(exception, *args) elif button_type == 'action': action_id = None args = ('model', 'ir.action', 'get_action_id', @@ -74,14 +72,13 @@ class Button(object): try: action_id = rpc.execute(*args) except TrytonServerError, exception: - action_id = common.process_exception(exception, self.form.window, - *args) + action_id = common.process_exception(exception, *args) if action_id: Action.execute(action_id, { 'model': self.form.screen.model_name, 'id': obj_id, 'ids': [obj_id], - }, self.form.window, context=ctx) + }, context=ctx) else: raise Exception('Unallowed button type') self.form.screen.reload(written=True) @@ -289,10 +286,10 @@ class _container(object): class ParserForm(ParserInterface): - def __init__(self, window, parent=None, attrs=None, screen=None, + def __init__(self, parent=None, attrs=None, screen=None, children_field=None): - super(ParserForm, self).__init__(window, parent=parent, attrs=attrs, - screen=screen, children_field=children_field) + super(ParserForm, self).__init__(parent=parent, attrs=attrs, + screen=screen, children_field=children_field) self.widget_id = 0 def parse(self, model_name, root_node, fields, notebook=None, paned=None, @@ -445,16 +442,6 @@ class ParserForm(ParserInterface): widget, widgets, buttons, spam, notebook_list2, cursor_widget2 = \ self.parse(model_name, node, fields, notebook, tooltips=tooltips) - max_width, max_height = -1, -1 - window_width, window_height = Main.get_main().window.get_size() - for i in xrange(notebook.get_n_pages()): - width, height = notebook.get_nth_page(i)\ - .get_child().get_child().size_request() - if width > max_width and width < window_width - 50: - max_width = width - if height > max_height and height < window_height - 50: - max_height = height - notebook.set_size_request(max_width + 20, max_height + 20) if not cursor_widget: cursor_widget = cursor_widget2 notebook_list.extend(notebook_list2) @@ -555,8 +542,7 @@ class ParserForm(ParserInterface): not attr_name in attrs: attrs[attr_name] = fields[name].attrs[attr_name] - widget_act = WIDGETS_TYPE[ftype][0](name, model_name, - self.window, attrs) + widget_act = WIDGETS_TYPE[ftype][0](name, model_name, attrs) self.widget_id += 1 widget_act.position = self.widget_id dict_widget.setdefault(name, []) @@ -674,8 +660,7 @@ class ParserForm(ParserInterface): obj_id = self.screen.current_record.id if obj_id < 0: common.message( - _('You need to save the record before adding translations!'), - parent=self.window) + _('You need to save the record before adding translations!')) return False obj_id = self.screen.current_record.save(force_reload=False) @@ -684,12 +669,11 @@ class ParserForm(ParserInterface): 'search', [('translatable', '=', '1')], rpc.CONTEXT) except TrytonServerError, exception: - common.process_exception(exception, self.window) + common.process_exception(exception) return False if not lang_ids: - common.message(_('No other language available!'), - parent=self.window) + common.message(_('No other language available!')) return False try: lang_ids += rpc.execute('model', 'ir.lang', @@ -699,7 +683,7 @@ class ParserForm(ParserInterface): 'read', lang_ids, ['code', 'name'], rpc.CONTEXT) except TrytonServerError, exception: - common.process_exception(exception, self.window) + common.process_exception(exception) return False code = rpc.CONTEXT.get('language', 'en_US') @@ -749,7 +733,8 @@ class ParserForm(ParserInterface): return None, False - win = gtk.Dialog(_('Add Translation'), self.window, + parent = common.get_toplevel_window() + win = gtk.Dialog(_('Add Translation'),parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) win.set_has_separator(True) win.vbox.set_spacing(5) @@ -783,7 +768,7 @@ class ParserForm(ParserInterface): val = rpc.execute('model', model_name, 'read', [obj_id], [name], context) except TrytonServerError, exception: - common.process_exception(exception, self.window) + common.process_exception(exception) return False val = val[0] if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL: @@ -836,15 +821,12 @@ class ParserForm(ParserInterface): try: rpc.execute(*args) except TrytonServerError, exception: - common.process_exception(exception, self.window, *args) - if response == gtk.RESPONSE_CANCEL: - self.window.present() - win.destroy() - return - self.screen.current_record.reload() - self.window.present() + common.process_exception(exception, *args) + if response != gtk.RESPONSE_CANCEL: + self.screen.current_record.reload() win.destroy() - return True + parent.present() + return response != gtk.RESPONSE_CANCEL from calendar import Calendar, DateTime from float import Float diff --git a/tryton/gui/window/view_form/view/form_gtk/progressbar.py b/tryton/gui/window/view_form/view/form_gtk/progressbar.py index 9c1618da78..24618ac174 100644 --- a/tryton/gui/window/view_form/view/form_gtk/progressbar.py +++ b/tryton/gui/window/view_form/view/form_gtk/progressbar.py @@ -14,9 +14,8 @@ class ProgressBar(WidgetInterface): 'top_to_bottom': gtk.PROGRESS_TOP_TO_BOTTOM, } - def __init__(self, field_name, model_name, window, attrs=None): - super(ProgressBar, self).__init__(field_name, model_name, window, - attrs=attrs) + def __init__(self, field_name, model_name, attrs=None): + super(ProgressBar, self).__init__(field_name, model_name, attrs=attrs) self.widget = gtk.ProgressBar() orientation = self.orientations.get(attrs.get('orientation', 'left_to_right'), gtk.PROGRESS_LEFT_TO_RIGHT) diff --git a/tryton/gui/window/view_form/view/form_gtk/reference.py b/tryton/gui/window/view_form/view/form_gtk/reference.py index 6d12ce9487..91a9c57bdd 100644 --- a/tryton/gui/window/view_form/view/form_gtk/reference.py +++ b/tryton/gui/window/view_form/view/form_gtk/reference.py @@ -18,9 +18,8 @@ _ = gettext.gettext class Reference(WidgetInterface): - def __init__(self, field_name, model_name, window, attrs=None): - super(Reference, self).__init__(field_name, model_name, window, - attrs=attrs) + def __init__(self, field_name, model_name, attrs=None): + super(Reference, self).__init__(field_name, model_name, attrs=attrs) self.widget = gtk.HBox(spacing=0) @@ -83,7 +82,7 @@ class Reference(WidgetInterface): selection = rpc.execute('model', self.model_name, selection, rpc.CONTEXT) except TrytonServerError, exception: - common.process_exception(exception, self.window) + common.process_exception(exception) selection = [] selection.sort(key=operator.itemgetter(1)) self.set_popdown(selection) @@ -152,19 +151,22 @@ class Reference(WidgetInterface): model, (obj_id, name) = value except ValueError: self.focus_out = True - return False + return if model and obj_id: if not leave: - screen = Screen(model, self.window, mode=['form']) + screen = Screen(model, mode=['form']) screen.load([obj_id]) - win = WinForm(screen, self.widget.get_toplevel()) - if win.run(): - if screen.save_current(): + def callback(result): + if result and screen.save_current(): value = (screen.current_record.id, screen.current_record.rec_name()) self.field.set_client(self.record, (model, value), force_change=True) - win.destroy() + self.focus_out = True + self.changed = True + self.display(self.record, self.field) + WinForm(screen, callback) + return elif model: if not self._readonly and ( self.wid_text.get_text() or not leave): domain = self.field.domain_get(self.record) @@ -182,22 +184,25 @@ class Reference(WidgetInterface): except TrytonServerError, exception: self.focus_out = True self.changed = True - common.process_exception(exception, self.window) - return False + common.process_exception(exception) + return if ids and len(ids) == 1: self.field.set_client(self.record, (model, (ids[0], ''))) self.display(self.record, self.field) self.focus_out = True self.changed = True - return True + return - win = WinSearch(model, sel_multi=False, ids=ids, context=context, - domain=domain, parent=self.widget.get_toplevel()) - ids = win.run() - if ids: - self.field.set_client(self.record, (model, (ids[0], ''))) - else: - self.field.set_client(self.record, ('', (name, name))) + def callback(ids): + if ids: + self.field.set_client(self.record, (model, (ids[0], ''))) + self.focus_out = True + self.changed = True + self.display(self.record, self.field) + WinSearch(model, callback, sel_multi=False, ids=ids, + context=context, domain=domain) + return + self.field.set_client(self.record, ('', (name, name))) self.focus_out = True self.changed = True self.display(self.record, self.field) @@ -206,7 +211,7 @@ class Reference(WidgetInterface): model = self.get_model() if not model: return - screen = Screen(model, self.window, mode=['form']) + screen = Screen(model, mode=['form']) win = WinForm(screen, self.widget.get_toplevel(), new=True) if win.run(): if screen.save_current(): @@ -272,8 +277,7 @@ class Reference(WidgetInterface): try: name = rpc.execute(*args) except TrytonServerError, exception: - name = common.process_exception(exception, self.window, - *args) + name = common.process_exception(exception, *args) if not name: name = '???' self.wid_text.set_text(name) diff --git a/tryton/gui/window/view_form/view/form_gtk/selection.py b/tryton/gui/window/view_form/view/form_gtk/selection.py index 745579417a..9c74a0dd0e 100644 --- a/tryton/gui/window/view_form/view/form_gtk/selection.py +++ b/tryton/gui/window/view_form/view/form_gtk/selection.py @@ -12,9 +12,8 @@ from tryton.exceptions import TrytonServerError class Selection(WidgetInterface): - def __init__(self, field_name, model_name, window, attrs=None): - super(Selection, self).__init__(field_name, model_name, window, - attrs=attrs) + def __init__(self, field_name, model_name, attrs=None): + super(Selection, self).__init__(field_name, model_name, attrs=attrs) self.widget = gtk.HBox(spacing=3) self.entry = gtk.ComboBoxEntry() @@ -45,7 +44,7 @@ class Selection(WidgetInterface): selection = rpc.execute('model', self.model_name, selection, rpc.CONTEXT) except TrytonServerError, exception: - common.process_exception(exception, self.window) + common.process_exception(exception) selection = [] self.selection = selection[:] if self.attrs.get('sort', True): @@ -67,7 +66,7 @@ class Selection(WidgetInterface): try: result = rpc.execute(*args) except TrytonServerError, exception: - result = common.process_exception(exception, self.window, args) + result = common.process_exception(exception, args) if isinstance(result, list): selection = [(x['id'], x['rec_name']) for x in result] selection.append((False, '')) diff --git a/tryton/gui/window/view_form/view/form_gtk/textbox.py b/tryton/gui/window/view_form/view/form_gtk/textbox.py index 040fee5989..ce4a3ede0b 100644 --- a/tryton/gui/window/view_form/view/form_gtk/textbox.py +++ b/tryton/gui/window/view_form/view/form_gtk/textbox.py @@ -13,9 +13,8 @@ except ImportError: class TextBox(WidgetInterface): - def __init__(self, field_name, model_name, window, attrs=None): - super(TextBox, self).__init__(field_name, model_name, window, - attrs=attrs) + def __init__(self, field_name, model_name, attrs=None): + super(TextBox, self).__init__(field_name, model_name, attrs=attrs) self.widget = gtk.HBox() self.scrolledwindow = gtk.ScrolledWindow() diff --git a/tryton/gui/window/view_form/view/form_gtk/url.py b/tryton/gui/window/view_form/view/form_gtk/url.py index 9844ab0f06..13be7537a8 100644 --- a/tryton/gui/window/view_form/view/form_gtk/url.py +++ b/tryton/gui/window/view_form/view/form_gtk/url.py @@ -10,8 +10,8 @@ import tryton.common as common class URL(Char): "url" - def __init__(self, field_name, model_name, window, attrs=None): - super(URL, self).__init__(field_name, model_name, window, attrs=attrs) + def __init__(self, field_name, model_name, attrs=None): + super(URL, self).__init__(field_name, model_name, attrs=attrs) self.tooltips = common.Tooltips() self.button = gtk.Button() diff --git a/tryton/gui/window/view_form/view/graph.py b/tryton/gui/window/view_form/view/graph.py index 584bf75c13..8ae7c48f2d 100644 --- a/tryton/gui/window/view_form/view/graph.py +++ b/tryton/gui/window/view_form/view/graph.py @@ -5,11 +5,10 @@ from interface import ParserView class ViewGraph(ParserView): - def __init__(self, window, screen, widget, children=None, - buttons=None, notebooks=None, cursor_widget=None, - children_field=None): - super(ViewGraph, self).__init__(window, screen, widget, children, - buttons, notebooks, cursor_widget, children_field) + def __init__(self, screen, widget, children=None, buttons=None, + notebooks=None, cursor_widget=None, children_field=None): + super(ViewGraph, self).__init__(screen, widget, children, buttons, + notebooks, cursor_widget, children_field) self.view_type = 'graph' self.widgets = children diff --git a/tryton/gui/window/view_form/view/graph_gtk/bar.py b/tryton/gui/window/view_form/view/graph_gtk/bar.py index a189ef0b23..73b248a003 100644 --- a/tryton/gui/window/view_form/view/graph_gtk/bar.py +++ b/tryton/gui/window/view_form/view/graph_gtk/bar.py @@ -115,12 +115,12 @@ class Bar(Graph): self.queue_draw_area(minx - 1, miny - 1, maxx - minx + 2, maxy - miny + 2) - def action(self, window): - super(Bar, self).action(window) + def action(self): + super(Bar, self).action() for bar in self.bars: if bar.highlight: ids = self.ids[bar.xname] - self.action_keyword(ids, window) + self.action_keyword(ids) class VerticalBar(Bar): diff --git a/tryton/gui/window/view_form/view/graph_gtk/graph.py b/tryton/gui/window/view_form/view/graph_gtk/graph.py index 2586d2c846..cda20f36a5 100644 --- a/tryton/gui/window/view_form/view/graph_gtk/graph.py +++ b/tryton/gui/window/view_form/view/graph_gtk/graph.py @@ -128,10 +128,10 @@ class Graph(gtk.DrawingArea): self.queue_draw() - def action(self, window): + def action(self): self.popup.hide() - def action_keyword(self, ids, window): + def action_keyword(self, ids): if not ids: return ctx = self.group.context.copy() @@ -146,7 +146,7 @@ class Graph(gtk.DrawingArea): else: hide = False with Window(hide_current=hide): - return Action.exec_keyword('graph_open', window, { + return Action.exec_keyword('graph_open', { 'model': self.model, 'id': ids[0], 'ids': ids, diff --git a/tryton/gui/window/view_form/view/graph_gtk/line.py b/tryton/gui/window/view_form/view/graph_gtk/line.py index b038d53da6..d4b1694059 100644 --- a/tryton/gui/window/view_form/view/graph_gtk/line.py +++ b/tryton/gui/window/view_form/view/graph_gtk/line.py @@ -201,12 +201,12 @@ class Line(Graph): super(Line, self).drawAxis(cr, width, height) self.drawLine(cr, 1.0, 0) - def action(self, window): - super(Line, self).action(window) + def action(self): + super(Line, self).action() for point in self.points: if point.highlight: ids = self.ids[point.xname] - self.action_keyword(ids, window) + self.action_keyword(ids) def YLabels(self): ylabels = super(Line, self).YLabels() diff --git a/tryton/gui/window/view_form/view/graph_gtk/parser.py b/tryton/gui/window/view_form/view/graph_gtk/parser.py index e08ac2b711..1311fb5bce 100644 --- a/tryton/gui/window/view_form/view/graph_gtk/parser.py +++ b/tryton/gui/window/view_form/view/graph_gtk/parser.py @@ -20,8 +20,9 @@ GRAPH_TYPE = { 'pie': Pie, } -def save(widget, graph, window): - dia = gtk.Dialog(_('Save As'), window, +def save(widget, graph): + parent = common.get_toplevel_window() + dia = gtk.Dialog(_('Save As'), parent, gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)) @@ -93,24 +94,24 @@ def save(widget, graph, window): gtk.MESSAGE_ERROR) else: break - window.present() + parent.present() dia.destroy() return -def button_press(widget, event, graph, window): +def button_press(widget, event, graph): if event.button == 3: menu = gtk.Menu() item = gtk.ImageMenuItem(_('Save As...')) img = gtk.Image() img.set_from_stock('tryton-save-as', gtk.ICON_SIZE_MENU) item.set_image(img) - item.connect('activate', save, graph, window) + item.connect('activate', save, graph) item.show() menu.append(item) menu.popup(None, None, None, event.button, event.time) return True elif event.button == 1: - graph.action(window) + graph.action() class ParserGraph(ParserInterface): @@ -145,6 +146,6 @@ class ParserGraph(ParserInterface): widget = GRAPH_TYPE[attrs.get('type', 'vbar')](xfield, yfields, attrs, model) event = gtk.EventBox() event.add(widget) - event.connect('button-press-event', button_press, widget, self.window) + event.connect('button-press-event', button_press, widget) return event, {'root': widget}, [], '', [], None diff --git a/tryton/gui/window/view_form/view/graph_gtk/pie.py b/tryton/gui/window/view_form/view/graph_gtk/pie.py index 42d155080d..feb0e46da7 100644 --- a/tryton/gui/window/view_form/view/graph_gtk/pie.py +++ b/tryton/gui/window/view_form/view/graph_gtk/pie.py @@ -156,12 +156,12 @@ class Pie(Graph): slice.highlight = False self.queue_draw() - def action(self, window): - super(Pie, self).action(window) + def action(self): + super(Pie, self).action() for slice in self.slices: if slice.highlight: ids = self.ids[slice.xname] - self.action_keyword(ids, window) + self.action_keyword(ids) class Slice(object): diff --git a/tryton/gui/window/view_form/view/interface.py b/tryton/gui/window/view_form/view/interface.py index 24b5d990ee..991a315394 100644 --- a/tryton/gui/window/view_form/view/interface.py +++ b/tryton/gui/window/view_form/view/interface.py @@ -5,9 +5,8 @@ class ParserInterface(object): - def __init__(self, window, parent=None, attrs=None, screen=None, + def __init__(self, parent=None, attrs=None, screen=None, children_field=None): - self.window = window self.parent = parent self.attrs = attrs self.title = None @@ -18,9 +17,8 @@ class ParserInterface(object): class ParserView(object): - def __init__(self, window, screen, widget, children=None, buttons=None, + def __init__(self, screen, widget, children=None, buttons=None, notebooks=None, cursor_widget=None, children_field=None): - self.window = window self.screen = screen self.widget = widget self.children = children diff --git a/tryton/gui/window/view_form/view/list.py b/tryton/gui/window/view_form/view/list.py index 9e4617c63a..e04ddc761c 100644 --- a/tryton/gui/window/view_form/view/list.py +++ b/tryton/gui/window/view_form/view/list.py @@ -238,10 +238,10 @@ class AdaptModelGroup(gtk.GenericTreeModel): class ViewList(ParserView): - def __init__(self, window, screen, widget, children=None, buttons=None, + def __init__(self, screen, widget, children=None, buttons=None, notebooks=None, cursor_widget=None, children_field=None): - super(ViewList, self).__init__(window, screen, widget, children, - buttons, notebooks, cursor_widget, children_field) + super(ViewList, self).__init__(screen, widget, children, buttons, + notebooks, cursor_widget, children_field) self.store = None self.view_type = 'tree' @@ -255,9 +255,6 @@ class ViewList(ParserView): viewport.add(scroll) self.widget_tree = self.widget - if isinstance(self.screen.window, gtk.Dialog): - width, height = self.widget_tree.size_request() - vbox.set_size_request(width or -1, height or -1) vbox.pack_start(viewport, expand=True, fill=True) self.widget_tree.screen = screen @@ -536,8 +533,7 @@ class ViewList(ParserView): try: relates = rpc.execute(*args) except TrytonServerError, exception: - relates = common.process_exception(exception, self.window, - *args) + relates = common.process_exception(exception, *args) if not relates: return False menu_entries = [] @@ -579,12 +575,11 @@ class ViewList(ParserView): context = {} act = action.copy() if not(value): - message(_('You must select a record to use the relation!'), - self.window) + message(_('You must select a record to use the relation!')) return False from tryton.gui.window.view_form.screen import Screen screen = Screen(self.screen.group.fields[ - path[1].name].attrs['relation'], self.window) + path[1].name].attrs['relation']) screen.load([value]) encoder = PYSONEncoder() act['domain'] = encoder.encode(screen.current_record.expr_eval( @@ -594,10 +589,10 @@ class ViewList(ParserView): data['model'] = self.screen.model_name data['id'] = value data['ids'] = [value] - return Action._exec_action(act, self.window, data, context) + return Action._exec_action(act, data, context) def click_and_action(self, atype, value, path): - return Action.exec_keyword(atype, self.window, { + return Action.exec_keyword(atype, { 'model': self.screen.group.fields[ path[1].name].attrs['relation'], 'id': value or False, diff --git a/tryton/gui/window/view_form/view/list_gtk/editabletree.py b/tryton/gui/window/view_form/view/list_gtk/editabletree.py index 1d5223505d..be2c8bf41c 100644 --- a/tryton/gui/window/view_form/view/list_gtk/editabletree.py +++ b/tryton/gui/window/view_form/view/list_gtk/editabletree.py @@ -32,12 +32,12 @@ class EditableTreeView(gtk.TreeView): return try: - real_value = cell.value_from_text(current_record, value) - field.set_client(current_record, real_value) + cell.value_from_text(current_record, value) except parser.UnsettableColumn: return - def on_open_remote(self, current_record, fieldname, create, value): + def on_open_remote(self, current_record, fieldname, create, value, + entry=None, callback=None): field = current_record[fieldname] cell = self.cells[fieldname] if value != cell.get_textual_value(current_record) or not value: @@ -45,13 +45,10 @@ class EditableTreeView(gtk.TreeView): else: changed = False try: - valid, value = cell.open_remote(current_record, create, - changed, value) - if valid: - field.set_client(current_record, value) + cell.open_remote(current_record, create, changed, value, + callback=callback) except NotImplementedError: pass - return cell.get_textual_value(current_record) def on_create_line(self): model = self.get_model() @@ -228,15 +225,19 @@ class EditableTreeView(gtk.TreeView): else: value = entry.get_active_text() entry.disconnect(entry.editing_done_id) - newval = self.on_open_remote(record, column.name, - create=(event.keyval==gtk.keysyms.F3), value=value) - if isinstance(entry, gtk.Entry): - entry.set_text(newval) - else: - entry.set_active_text(newval) - entry.editing_done_id = entry.connect('editing_done', - self.on_editing_done) - self.set_cursor(path, column, True) + def callback(): + cell = self.cells[column.name] + value = cell.get_textual_value(record) + if isinstance(entry, gtk.Entry): + entry.set_text(value) + else: + entry.set_active_text(value) + entry.editing_done_id = entry.connect('editing_done', + self.on_editing_done) + self.set_cursor(path, column, True) + self.on_open_remote(record, column.name, + create=(event.keyval==gtk.keysyms.F3), value=value, + callback=callback) else: field = record[column.name] if isinstance(entry, gtk.Entry): diff --git a/tryton/gui/window/view_form/view/list_gtk/parser.py b/tryton/gui/window/view_form/view/list_gtk/parser.py index ae118753ef..607a0ef371 100644 --- a/tryton/gui/window/view_form/view/list_gtk/parser.py +++ b/tryton/gui/window/view_form/view/list_gtk/parser.py @@ -69,9 +69,9 @@ def sort_model(column, treeview, screen): class ParserTree(ParserInterface): - def __init__(self, window, parent=None, attrs=None, screen=None, + def __init__(self, parent=None, attrs=None, screen=None, children_field=None): - super(ParserTree, self).__init__(window, parent, attrs, screen, + super(ParserTree, self).__init__(parent, attrs, screen, children_field=children_field) self.treeview = None @@ -113,7 +113,7 @@ class ParserTree(ParserInterface): node_attrs[attr_name] = fields[fname].attrs[attr_name] cell = CELLTYPES.get(node_attrs.get('widget', fields[fname].attrs['type']))(fname, model_name, - treeview, self.window, node_attrs) + treeview, node_attrs) treeview.cells[fname] = cell renderer = cell.renderer @@ -214,7 +214,7 @@ class ParserTree(ParserInterface): dict_widget[i] = (fname, label, label_sum, digits) elif node.localName == 'button': #TODO add shortcut - cell = Button(treeview, self.window, self.screen, node_attrs) + cell = Button(treeview, self.screen, node_attrs) button_list.append(cell) renderer = cell.renderer string = node_attrs.get('string', _('Unknown')) @@ -259,14 +259,13 @@ class ParserTree(ParserInterface): class Char(object): - def __init__(self, field_name, model_name, treeview, window, attrs=None): + def __init__(self, field_name, model_name, treeview, attrs=None): super(Char, self).__init__() self.field_name = field_name self.model_name = model_name self.attrs = attrs or {} self.renderer = CellRendererText() self.treeview = treeview - self.window = window def setter(self, column, cell, store, iter): record = store.get_value(iter, 0) @@ -338,7 +337,8 @@ class Char(object): def get_color(self, record): return record.expr_eval(self.treeview.colors, check_load=False) - def open_remote(self, record, create, changed=False, text=None): + def open_remote(self, record, create, changed=False, text=None, + callback=None): raise NotImplementedError def get_textual_value(self, record): @@ -347,17 +347,19 @@ class Char(object): return record[self.field_name].get_client(record) or '' def value_from_text(self, record, text): - return text + field = record[self.field_name] + field.set_client(record, text) class Int(Char): - def __init__(self, field_name, model_name, treeview, window, attrs=None): - super(Int, self).__init__(field_name, model_name, treeview, window, - attrs=attrs) + def __init__(self, field_name, model_name, treeview, attrs=None): + super(Int, self).__init__(field_name, model_name, treeview, + attrs=attrs) self.renderer = CellRendererInteger() def value_from_text(self, record, text): - return int(text) + field = record[self.field_name] + field.set_client(record, int(text)) def get_textual_value(self, record): return locale.format('%d', @@ -365,9 +367,9 @@ class Int(Char): class Boolean(Int): - def __init__(self, field_name, model_name, treeview, window, attrs=None): - super(Boolean, self).__init__(field_name, model_name, treeview, window, - attrs=attrs) + def __init__(self, field_name, model_name, treeview, attrs=None): + super(Boolean, self).__init__(field_name, model_name, treeview, + attrs=attrs) self.renderer = CellRendererToggle() self.renderer.connect('toggled', self._sig_toggled) @@ -388,9 +390,9 @@ class Boolean(Int): class Date(Char): server_format = DT_FORMAT - def __init__(self, field_name, model_name, treeview, window, attrs=None): - super(Date, self).__init__(field_name, model_name, treeview, window, - attrs=attrs) + def __init__(self, field_name, model_name, treeview, attrs=None): + super(Date, self).__init__(field_name, model_name, treeview, + attrs=attrs) self.display_format = date_format() self.renderer = CellRendererDate(self.display_format) @@ -402,21 +404,22 @@ class Date(Char): return common.datetime_strftime(date, self.display_format) def value_from_text(self, record, text): - if not text: - return False + field = record[self.field_name] + date = False try: date = datetime.date(*time.strptime(text, self.display_format)[:3]) + date = common.datetime_strftime(date, self.server_format) except ValueError: - return False - return common.datetime_strftime(date, self.server_format) + date = False + field.set_client(record, date) class Datetime(Date): server_format = DHM_FORMAT - def __init__(self, field_name, model_name, treeview, window, attrs=None): + def __init__(self, field_name, model_name, treeview, attrs=None): super(Datetime, self).__init__(field_name, model_name, treeview, - window, attrs=attrs) + attrs=attrs) self.display_format = date_format() + ' ' + HM_FORMAT self.renderer.format = self.display_format @@ -430,22 +433,23 @@ class Datetime(Date): return common.datetime_strftime(date, self.display_format) def value_from_text(self, record, text): - if not text: - return False + field = record[self.field_name] + date = False try: date = datetime.datetime(*time.strptime(text, self.display_format)[:6]) + date = common.timezoned_date(date) + date = common.datetime_strftime(date, self.server_format) except ValueError: - return False - date = common.timezoned_date(date) - return common.datetime_strftime(date, self.server_format) + date = False + field.set_client(record, date) class Float(Char): - def __init__(self, field_name, model_name, treeview, window, attrs=None): - super(Float, self).__init__(field_name, model_name, treeview, window, - attrs=attrs) + def __init__(self, field_name, model_name, treeview, attrs=None): + super(Float, self).__init__(field_name, model_name, treeview, + attrs=attrs) self.renderer = CellRendererFloat() def setter(self, column, cell, store, iter): @@ -468,17 +472,19 @@ class Float(Char): record[self.field_name].get_client(record) or 0.0, True) def value_from_text(self, record, text): + field = record[self.field_name] try: - return locale.atof(text) + value = locale.atof(text) except ValueError: - return 0.0 + value = 0.0 + field.set_client(record, value) class FloatTime(Char): - def __init__(self, field_name, model_name, treeview, window, attrs=None): + def __init__(self, field_name, model_name, treeview, attrs=None): super(FloatTime, self).__init__(field_name, model_name, treeview, - window, attrs=attrs) + attrs=attrs) self.conv = None if attrs and attrs.get('float_time'): self.conv = rpc.CONTEXT.get(attrs['float_time']) @@ -488,7 +494,8 @@ class FloatTime(Char): return common.float_time_to_text(val, self.conv) def value_from_text(self, record, text): - return common.text_to_float_time(text, self.conv) + field = record[self.field_name] + field.set_client(record, common.text_to_float_time(text, self.conv)) class M2O(Char): @@ -508,18 +515,23 @@ class M2O(Char): dom = domain args = ('model', relation, 'search', dom, 0, None, None, context) + def callback(value): + field.set_client(record, value) try: ids = rpc.execute(*args) except TrytonServerError, exception: - ids = common.process_exception(exception, self.window, *args) + ids = common.process_exception(exception, *args) if not ids: - return '???' + callback('???') + return if len(ids) != 1: - return self.search_remote(relation, ids, - domain=domain, context=context)[0] - return ids[0] + self.search_remote(record, relation, ids, domain=domain, + context=context) + return + callback(ids[0]) - def open_remote(self, record, create=True, changed=False, text=None): + def open_remote(self, record, create=True, changed=False, text=None, + callback=None): field = record.group.fields[self.field_name] relation = field.attrs['relation'] @@ -538,54 +550,61 @@ class M2O(Char): try: ids = rpc.execute(*args) except TrytonServerError, exception: - ids = common.process_exception(exception, self.window, *args) + ids = common.process_exception(exception, *args) if not ids: - return False, False + field.set_client(record, False) + if callback: + callback() + return if len(ids) == 1: - return True, ids[0] - searched = self.search_remote(relation, ids, domain=domain, - context=context) - if searched[0]: - return True, searched - return False, False - screen = Screen(relation, self.window, domain=domain, context=context, - mode=['form']) + field.set_client(record, ids[0]) + if callback: + callback() + return + self.search_remote(record, relation, ids, domain=domain, + context=context, callback=callback) + return + screen = Screen(relation, domain=domain, context=context, + mode=['form']) + + def open_callback(result): + if result and screen.save_current(): + value = (screen.current_record.id, + screen.current_record.rec_name()) + field.set_client(record, value) + if callback: + callback() if obj_id: screen.load([obj_id]) - win = WinForm(screen, self.window) + WinForm(screen, open_callback) else: - win = WinForm(screen, self.window, new=True) - value = False - if win.run(): - if screen.save_current(): - value = (screen.current_record.id, - screen.current_record.rec_name()) - win.destroy() - if value: - return True, value - else: - return False, False + WinForm(screen, open_callback, new=True) + + def search_remote(self, record, relation, ids=None, domain=None, + context=None, callback=None): + field = record.group.fields[self.field_name] + def search_callback(found): + value = None + if found: + args = ('model', relation, 'read', found[0], ['rec_name'], + context) + try: + res = rpc.execute(*args) + except TrytonServerError, exception: + res = common.process_exception(exception, *args) + if res: + value = (found[0], res['rec_name']) + field.set_client(record, value) + if callback: + callback() + WinSearch(relation, search_callback, sel_multi=False, ids=ids, + context=context, domain=domain) - def search_remote(self, relation, ids=None, domain=None, context=None): - win = WinSearch(relation, sel_multi=False, ids=ids, context=context, - domain=domain, parent=self.window) - found = win.run() - if found: - args = ('model', relation, 'read', found[0], ['rec_name'], - context) - try: - res = rpc.execute(*args) - except TrytonServerError, exception: - res = common.process_exception(exception, self.window, *args) - if not res: - return False, None - return found[0], res['rec_name'] - else: - return False, None class O2O(M2O): pass + class UnsettableColumn(Exception): def __init__(self): @@ -605,19 +624,20 @@ class O2M(Char): def value_from_text(self, record, text): pass - def open_remote(self, record, create=True, changed=False, text=None): + def open_remote(self, record, create=True, changed=False, text=None, + callback=None): group = record.value[self.field_name] field = record.group.fields[self.field_name] relation = field.attrs['relation'] context = field.context_get(record) - screen = Screen(relation, self.window, mode=['tree', 'form'], - exclude_field=field.attrs.get('relation_field')) + screen = Screen(relation, mode=['tree', 'form'], + exclude_field=field.attrs.get('relation_field')) screen.group = group - win = WinForm(screen, self.window, view_type='tree', context=context) - win.run() - win.destroy() - return False, False + def open_callback(result): + if callback: + callback() + WinForm(screen, open_callback, view_type='tree', context=context) class M2M(Char): @@ -631,11 +651,12 @@ class M2M(Char): get_client(record))) + ' )' def value_from_text(self, record, text): - if not text: - return [] - if not (text[0] != '('): - return record[self.field_name].get(record) field = record[self.field_name] + if not text: + field.set_client(record, []) + return + if not (text[0] != '('): + return relation = field.attrs['relation'] domain = field.domain_get(record) context = field.context_get(record) @@ -649,15 +670,18 @@ class M2M(Char): try: ids = rpc.execute(*args) except TrytonServerError, exception: - ids = common.process_exception(exception, self.window, *args) + ids = common.process_exception(exception, *args) if ids is False: - return [] - win = WinSearch(relation, sel_multi=True, ids=ids, context=context, - domain=domain, parent=self.window) - found = win.run() - return found or [] + field.set_client(record, []) + return + def callback(result): + field.set_client(record, result or []) + WinSearch(relation, callback, sel_multi=True, ids=ids, context=context, + domain=domain) + return - def open_remote(self, record, create=True, changed=False, text=None): + def open_remote(self, record, create=True, changed=False, text=None, + callback=None): field = record[self.field_name] relation = field.attrs['relation'] context = field.context_get(record) @@ -669,20 +693,26 @@ class M2M(Char): try: ids = rpc.execute(*args) except TrytonServerError, exception: - ids = common.process_exception(exception, self.window, *args) + ids = common.process_exception(exception, *args) if ids is False: - return False, None + field.set_client(record, False) + if callback: + callback() if ids and len(ids)==1: - return True, ids + field.set_client(record, ids) + if callback: + callback() + return else: ids = [x.id for x in field.get_client(record)] - win = WinSearch(relation, sel_multi=True, ids=ids, context=context, - domain=domain, parent=self.window) - found = win.run() - if found: - return True, found - else: - return False, None + def open_callback(result): + if result: + field.set_client(record, result) + if callback: + callback() + WinSearch(relation, open_callback, sel_multi=True, ids=ids, context=context, + domain=domain) + class Selection(Char): @@ -698,8 +728,7 @@ class Selection(Char): try: selection = rpc.execute(*args) except TrytonServerError, exception: - selection = (common.process_exception(exception, self.window, - args) or []) + selection = (common.process_exception(exception, args) or []) self.selection = selection[:] if self.attrs.get('sort', True): selection.sort(key=operator.itemgetter(1)) @@ -726,7 +755,8 @@ class Selection(Char): return dict(self.selection).get(value, '') def value_from_text(self, record, text): - return self._selection.get(text, False), text + field = record[self.field_name] + field.set_client(record, self._selection.get(text, False)) def editing_started(self, cell, editable, path): store = self.treeview.get_model() @@ -758,7 +788,7 @@ class Selection(Char): try: result = rpc.execute(*args) except TrytonServerError, exception: - result = common.process_exception(exception, self.window, *args) + result = common.process_exception(exception, *args) if isinstance(result, list): selection = [(x['id'], x['rec_name']) for x in result] @@ -775,9 +805,9 @@ class Selection(Char): class Reference(Char): - def __init__(self, field_name, model_name, treeview, window, attrs=None): + def __init__(self, field_name, model_name, treeview, attrs=None): super(Reference, self).__init__(field_name, model_name, treeview, - window, attrs=attrs) + attrs=attrs) self._selection = {} selection = attrs.get('selection', []) if not isinstance(selection, (list, tuple)): @@ -785,7 +815,7 @@ class Reference(Char): selection = rpc.execute('model', model_name, selection, rpc.CONTEXT) except TrytonServerError, exception: - common.process_exception(exception, self.window) + common.process_exception(exception) selection = [] selection.sort(key=operator.itemgetter(1)) for i, j in selection: @@ -804,8 +834,7 @@ class Reference(Char): try: res = rpc.execute(*args) except TrytonServerError, exception: - res = common.process_exception(exception, self.window, - *args) + res = common.process_exception(exception, *args) if not res: name = '???' else: @@ -826,7 +855,7 @@ class ProgressBar(object): 'top_to_bottom': gtk.PROGRESS_TOP_TO_BOTTOM, } - def __init__(self, field_name, model_name, treeview, window, attrs=None): + def __init__(self, field_name, model_name, treeview, attrs=None): super(ProgressBar, self).__init__() self.field_name = field_name self.model_name = model_name @@ -836,7 +865,6 @@ class ProgressBar(object): 'left_to_right'), gtk.PROGRESS_LEFT_TO_RIGHT) self.renderer.set_property('orientation', orientation) self.treeview = treeview - self.window = window def setter(self, column, cell, store, iter): record = store.get_value(iter, 0) @@ -849,24 +877,25 @@ class ProgressBar(object): text = locale.format('%.' + str(digit) + 'f', value, True) cell.set_property('text', text + '%') - def open_remote(self, record, create, changed=False, text=None): + def open_remote(self, record, create, changed=False, text=None, + callback=None): raise NotImplementedError def get_textual_value(self, record): return record[self.field_name].get_client(record) or '' def value_from_text(self, record, text): - return float(text) + field = record[self.field_name] + field.set_client(record, float(text)) class Button(object): - def __init__(self, treeview, window, screen, attrs=None): + def __init__(self, treeview, screen, attrs=None): super(Button, self).__init__() self.attrs = attrs or {} self.renderer = CellRendererButton(attrs.get('string', _('Unknown'))) self.treeview = treeview - self.window = window self.screen = screen self.renderer.connect('clicked', self.button_clicked) @@ -887,7 +916,7 @@ class Button(object): obj_id = self.screen.save_current() if obj_id: if not self.attrs.get('confirm', False) or \ - common.sur(self.attrs['confirm'], self.window): + common.sur(self.attrs['confirm']): button_type = self.attrs.get('type', 'workflow') ctx = rpc.CONTEXT.copy() ctx.update(record.context_get()) @@ -898,14 +927,14 @@ class Button(object): try: rpc.execute(*args) except TrytonServerError, exception: - common.process_exception(exception, self.window, *args) + common.process_exception(exception, *args) elif button_type == 'object': args = ('model', self.screen.model_name, self.attrs['name'], [obj_id], ctx) try: rpc.execute(*args) except TrytonServerError, exception: - common.process_exception(exception, self.window, *args) + common.process_exception(exception, *args) elif button_type == 'action': action_id = None args = ('model', 'ir.action', 'get_action_id', @@ -913,14 +942,13 @@ class Button(object): try: action_id = rpc.execute(*args) except TrytonServerError, exception: - action_id = common.process_exception(exception, - self.window, *args) + action_id = common.process_exception(exception, *args) if action_id: Action.execute(action_id, { 'model': self.screen.model_name, 'id': obj_id, 'ids': [obj_id], - }, self.window, context=ctx) + }, context=ctx) else: raise TrytonError('Unallowed button type') self.screen.reload(written=True) diff --git a/tryton/gui/window/view_form/view/screen_container.py b/tryton/gui/window/view_form/view/screen_container.py index 0e39c41d3c..291b453025 100644 --- a/tryton/gui/window/view_form/view/screen_container.py +++ b/tryton/gui/window/view_form/view/screen_container.py @@ -114,6 +114,3 @@ class ScreenContainer(object): self.viewport.remove(self.viewport.get_child()) self.viewport.add(widget) self.viewport.show_all() - - def size_get(self): - return self.viewport.get_child().size_request() diff --git a/tryton/gui/window/view_form/view/widget_parse.py b/tryton/gui/window/view_form/view/widget_parse.py index 1a6bf37b04..da554265b8 100644 --- a/tryton/gui/window/view_form/view/widget_parse.py +++ b/tryton/gui/window/view_form/view/widget_parse.py @@ -34,13 +34,13 @@ class WidgetParse(ParserInterface): if not node.nodeType == node.ELEMENT_NODE: continue if node.localName in PARSERS: - widget = PARSERS[node.localName](self.window, self.parent, - self.attrs, screen, children_field) + widget = PARSERS[node.localName](self.parent, self.attrs, + screen, children_field) wid, child, buttons, on_write, notebooks, cursor_widget = \ widget.parse(screen.model_name, node, fields) screen.set_on_write(on_write) - res = PARSERS2[node.localName](self.window, screen, wid, child, - buttons, notebooks, cursor_widget, children_field) + res = PARSERS2[node.localName](screen, wid, child, buttons, + notebooks, cursor_widget, children_field) res.title = widget.title widget = res break diff --git a/tryton/gui/window/view_form/widget_search/calendar.py b/tryton/gui/window/view_form/widget_search/calendar.py index 1f27e6ec7b..2c79bf056a 100644 --- a/tryton/gui/window/view_form/widget_search/calendar.py +++ b/tryton/gui/window/view_form/widget_search/calendar.py @@ -8,6 +8,7 @@ import locale from interface import Interface from tryton.common import DT_FORMAT, DHM_FORMAT, TRYTON_ICON from tryton.common import date_widget, Tooltips, datetime_strftime +from tryton.common import get_toplevel_window from tryton.translate import date_format import gobject @@ -16,10 +17,10 @@ _ = gettext.gettext class Calendar(Interface): - def __init__(self, name, parent, attrs=None, context=None, + def __init__(self, name, attrs=None, context=None, on_change=None): - super(Calendar, self).__init__(name, parent, attrs=attrs, - context=context, on_change=on_change) + super(Calendar, self).__init__(name, attrs=attrs, context=context, + on_change=on_change) tooltips = Tooltips() self.widget = gtk.HBox(spacing=3) @@ -54,8 +55,7 @@ class Calendar(Interface): self.eb1 = gtk.EventBox() tooltips.set_tip(self.eb1, _('Open the calendar')) self.eb1.set_events(gtk.gdk.BUTTON_PRESS) - self.eb1.connect('button_press_event', self.cal_open, self.entry1, - parent) + self.eb1.connect('button_press_event', self.cal_open, self.entry1) img = gtk.Image() img.set_from_stock('tryton-find', gtk.ICON_SIZE_BUTTON) img.set_alignment(0.5, 0.5) @@ -76,8 +76,7 @@ class Calendar(Interface): self.eb2 = gtk.EventBox() tooltips.set_tip(self.eb2, _('Open the calendar')) self.eb2.set_events(gtk.gdk.BUTTON_PRESS) - self.eb2.connect('button_press_event', self.cal_open, self.entry2, - parent) + self.eb2.connect('button_press_event', self.cal_open, self.entry2) img = gtk.Image() img.set_from_stock('tryton-find', gtk.ICON_SIZE_BUTTON) img.set_alignment(0.5, 0.5) @@ -161,7 +160,8 @@ class Calendar(Interface): value = property(_value_get, _value_set) - def cal_open(self, widget, event, dest, parent=None): + def cal_open(self, widget, event, dest): + parent = get_toplevel_window() win = gtk.Dialog(_('Date selection'), parent, gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, @@ -193,6 +193,7 @@ class Calendar(Interface): dest.set_text(datetime_strftime(date, self.format)) self.on_change() win.destroy() + parent.present() def clear(self): self.value = ('=', '') diff --git a/tryton/gui/window/view_form/widget_search/char.py b/tryton/gui/window/view_form/widget_search/char.py index 8474fe3421..d653883d6b 100644 --- a/tryton/gui/window/view_form/widget_search/char.py +++ b/tryton/gui/window/view_form/widget_search/char.py @@ -10,10 +10,9 @@ _ = gettext.gettext class Char(Interface): - def __init__(self, name, parent, attrs=None, context=None, - on_change=None): - super(Char, self).__init__(name, parent, attrs=attrs, context=context, - on_change=on_change) + def __init__(self, name, attrs=None, context=None, on_change=None): + super(Char, self).__init__(name, attrs=attrs, context=context, + on_change=on_change) self.widget = gtk.HBox() diff --git a/tryton/gui/window/view_form/widget_search/checkbox.py b/tryton/gui/window/view_form/widget_search/checkbox.py index d357daae7a..0306d36f10 100644 --- a/tryton/gui/window/view_form/widget_search/checkbox.py +++ b/tryton/gui/window/view_form/widget_search/checkbox.py @@ -9,10 +9,9 @@ _ = gettext.gettext class CheckBox(Interface): - def __init__(self, name, parent, attrs=None, context=None, - on_change=None): - super(CheckBox, self).__init__(name, parent, attrs=attrs, - context=context, on_change=on_change) + def __init__(self, name, attrs=None, context=None, on_change=None): + super(CheckBox, self).__init__(name, attrs=attrs, context=context, + on_change=on_change) self.widget = gtk.combo_box_entry_new_text() self.widget.child.set_editable(True) diff --git a/tryton/gui/window/view_form/widget_search/float.py b/tryton/gui/window/view_form/widget_search/float.py index 8bc46588f2..c6cdd40305 100644 --- a/tryton/gui/window/view_form/widget_search/float.py +++ b/tryton/gui/window/view_form/widget_search/float.py @@ -10,10 +10,9 @@ _ = gettext.gettext class Float(Integer): - def __init__(self, name, parent, attrs=None, context=None, - on_change=None): - super(Float, self).__init__(name, parent, attrs=attrs, context=context, - on_change=on_change) + def __init__(self, name, attrs=None, context=None, on_change=None): + super(Float, self).__init__(name, attrs=attrs, context=context, + on_change=on_change) if isinstance(self.attrs.get('digits'), str): self.digits = (16, 2) else: diff --git a/tryton/gui/window/view_form/widget_search/form.py b/tryton/gui/window/view_form/widget_search/form.py index 4086d7833e..fca1902f45 100644 --- a/tryton/gui/window/view_form/widget_search/form.py +++ b/tryton/gui/window/view_form/widget_search/form.py @@ -69,10 +69,8 @@ class _container(object): class Parse(object): - def __init__(self, parent, fields, model='', context=None, - on_change=None): + def __init__(self, fields, model='', context=None, on_change=None): self.fields = fields - self.parent = parent self.model = model self.col = CONFIG['client.modepda'] and 1 or 6 self.focusable = None @@ -111,7 +109,7 @@ class Parse(object): self.fields[str(attrs['name'])]['model']=self.model if ftype not in WIDGETS_TYPE: return False - widget_act = WIDGETS_TYPE[ftype][0](str(attrs['name']), self.parent, + widget_act = WIDGETS_TYPE[ftype][0](str(attrs['name']), attrs=self.fields[attrs['name']], context=self.context, on_change=self.on_change) if 'string' in self.fields[str(attrs['name'])]: @@ -195,15 +193,13 @@ class Parse(object): class Form(object): - def __init__(self, view, model=None, parent=None, domain=None, - call=None, context=None): + def __init__(self, view, model=None, domain=None, call=None, context=None): if domain is None: domain = [] if context is None: context = {} - parser = Parse(parent, view['fields'], model=model, context=context, - on_change=self.on_change) - self.parent = parent + parser = Parse(view['fields'], model=model, context=context, + on_change=self.on_change) self.fields = view['fields'] self.model = model self.parser = parser diff --git a/tryton/gui/window/view_form/widget_search/integer.py b/tryton/gui/window/view_form/widget_search/integer.py index 4ecab4e9ac..082cf02450 100644 --- a/tryton/gui/window/view_form/widget_search/integer.py +++ b/tryton/gui/window/view_form/widget_search/integer.py @@ -11,10 +11,9 @@ _ = gettext.gettext class Integer(Interface): - def __init__(self, name, parent, attrs=None, context=None, - on_change=None): - super(Integer, self).__init__(name, parent, attrs=attrs, - context=context, on_change=on_change) + def __init__(self, name, attrs=None, context=None, on_change=None): + super(Integer, self).__init__(name, attrs=attrs, context=context, + on_change=on_change) self.widget = gtk.HBox(spacing=3) self.liststore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING) diff --git a/tryton/gui/window/view_form/widget_search/interface.py b/tryton/gui/window/view_form/widget_search/interface.py index 6d400f6784..25e6c97a69 100644 --- a/tryton/gui/window/view_form/widget_search/interface.py +++ b/tryton/gui/window/view_form/widget_search/interface.py @@ -8,11 +8,10 @@ _ = gettext.gettext class Interface(object): "Interface for search widget" - def __init__(self, name, parent, attrs=None, context=None, on_change=None): + def __init__(self, name, attrs=None, context=None, on_change=None): if attrs is None: attrs = {} self._value = None - self.parent = parent self.name = name self.model = attrs.get('model', None) self.attrs = attrs or {} diff --git a/tryton/gui/window/view_form/widget_search/reference.py b/tryton/gui/window/view_form/widget_search/reference.py index 5a10761886..907637c15e 100644 --- a/tryton/gui/window/view_form/widget_search/reference.py +++ b/tryton/gui/window/view_form/widget_search/reference.py @@ -13,10 +13,9 @@ _ = gettext.gettext class Reference(Interface): - def __init__(self, name, parent, attrs=None, context=None, - on_change=None): - super(Reference, self).__init__(name, parent, attrs=attrs, - context=context, on_change=on_change) + def __init__(self, name, attrs=None, context=None, on_change=None): + super(Reference, self).__init__(name, attrs=attrs, context=context, + on_change=on_change) self.widget = gtk.HBox() @@ -49,7 +48,7 @@ class Reference(Interface): 0, None, None, ['rec_name'], rpc.CONTEXT) selection = [(x['id'], x['rec_name']) for x in result] except TrytonServerError, exception: - common.process_exception(exception, parent) + common.process_exception(exception) selection = [] else: if not isinstance(selection, (list, tuple)): @@ -57,7 +56,7 @@ class Reference(Interface): selection = rpc.execute('model', self.attrs['model'], selection, rpc.CONTEXT) except TrytonServerError, exception: - common.process_exception(exception, parent) + common.process_exception(exception) selection = [] selection.sort(lambda x, y: cmp(x[1], y[1])) self.attrs['selection'] = selection diff --git a/tryton/gui/window/view_form/widget_search/selection.py b/tryton/gui/window/view_form/widget_search/selection.py index 6a4de7b33d..9399e9fdc0 100644 --- a/tryton/gui/window/view_form/widget_search/selection.py +++ b/tryton/gui/window/view_form/widget_search/selection.py @@ -14,10 +14,9 @@ _ = gettext.gettext class Selection(Interface): - def __init__(self, name, parent, attrs=None, context=None, - on_change=None): - super(Selection, self).__init__(name, parent, attrs=attrs, - context=context, on_change=on_change) + def __init__(self, name, attrs=None, context=None, on_change=None): + super(Selection, self).__init__(name, attrs=attrs, context=context, + on_change=on_change) self.widget = gtk.HBox() @@ -53,7 +52,7 @@ class Selection(Interface): ['rec_name'], rpc.CONTEXT) selection = [(x['id'], x['rec_name']) for x in result] except TrytonServerError, exception: - common.process_exception(exception, parent) + common.process_exception(exception) selection = [] else: if not isinstance(selection, (list, tuple)): @@ -61,7 +60,7 @@ class Selection(Interface): selection = rpc.execute('model', self.attrs['model'], selection, rpc.CONTEXT) except TrytonServerError, exception: - common.process_exception(exception, parent) + common.process_exception(exception) selection = [] selection.sort(key=operator.itemgetter(1)) self.attrs['selection'] = selection diff --git a/tryton/gui/window/win_export.py b/tryton/gui/window/win_export.py index d7350a4800..3ece37ec99 100644 --- a/tryton/gui/window/win_export.py +++ b/tryton/gui/window/win_export.py @@ -18,10 +18,11 @@ _ = gettext.gettext class WinExport(object): "Window export" - def __init__(self, model, ids, parent, context=None): + def __init__(self, model, ids, context=None): + self.parent = common.get_toplevel_window() self.dialog = gtk.Dialog( title= _("Export to CSV"), - parent=parent, + parent=self.parent, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT | gtk.WIN_POS_CENTER_ON_PARENT) self.dialog.set_icon(TRYTON_ICON) @@ -162,8 +163,6 @@ class WinExport(object): self.fields_data = {} self.context = context - self.parent = parent - self.view1 = gtk.TreeView() self.view1.get_selection().set_mode(gtk.SELECTION_MULTIPLE) self.view1.connect('row-expanded', self.on_row_expanded) @@ -241,7 +240,7 @@ class WinExport(object): try: return rpc.execute(*args) except TrytonServerError, exception: - return common.process_exception(exception, self.parent, *args) + return common.process_exception(exception, *args) def on_row_expanded(self, treeview, iter, path): child = self.model1.iter_children(iter) @@ -279,15 +278,14 @@ class WinExport(object): try: export_ids = rpc.execute(*args) except TrytonServerError, exception: - export_ids = common.process_exception(exception, self.parent, - *args) + export_ids = common.process_exception(exception, *args) if not export_ids: return args = ('model', 'ir.export', 'read', export_ids, None, rpc.CONTEXT) try: exports = rpc.execute(*args) except TrytonServerError, exception: - exports = common.process_exception(exception, self.parent, *args) + exports = common.process_exception(exception, *args) if not exports: return args = ('model', 'ir.export.line', 'read', @@ -296,7 +294,7 @@ class WinExport(object): try: lines = rpc.execute(*args) except TrytonServerError, exception: - lines = common.process_exception(exception, self.parent, *args) + lines = common.process_exception(exception, *args) if not lines: return id2lines = {} @@ -310,7 +308,7 @@ class WinExport(object): self.pref_export.set_model(self.predef_model) def add_predef(self, widget): - name = common.ask(_('What is the name of this export?'), self.parent) + name = common.ask(_('What is the name of this export?')) if not name: return iter = self.model2.get_iter_root() @@ -398,10 +396,9 @@ class WinExport(object): self.export_csv(fname, fields2, result, self.wid_write_field_names.get_active(), popup=False) os.close(fileno) - common.file_open(fname, 'csv', self.parent) + common.file_open(fname, 'csv') else: fname = common.file_selection(_('Save As...'), - parent=self.parent, action=gtk.FILE_CHOOSER_ACTION_SAVE) if fname: self.export_csv(fname, fields2, result, @@ -429,15 +426,13 @@ class WinExport(object): file_p.close() if popup: if len(result) == 1: - common.message(_('%d record saved!') % len(result), - self.parent) + common.message(_('%d record saved!') % len(result)) else: - common.message(_('%d records saved!') % len(result), - self.parent) + common.message(_('%d records saved!') % len(result)) return True except IOError, exception: common.warning(_("Operation failed!\nError message:\n%s") \ - % (exception.args[0],), self.parent, _('Error')) + % (exception.args[0],), _('Error')) return False def datas_read(self, ids, model, fields, context=None): diff --git a/tryton/gui/window/win_form.py b/tryton/gui/window/win_form.py index 504cc636ca..c81cf0c286 100644 --- a/tryton/gui/window/win_form.py +++ b/tryton/gui/window/win_form.py @@ -7,18 +7,19 @@ import gtk import pango import gettext from tryton.exceptions import TrytonServerError +from tryton.gui.window.nomodal import NoModal _ = gettext.gettext -class WinForm(object): +class WinForm(NoModal): "Form window" - def __init__(self, screen, parent, view_type='form', new=False, - many=False, context=None): - - self.parent = parent + def __init__(self, screen, callback, view_type='form', + new=False, many=False, context=None): + NoModal.__init__(self) self.screen = screen + self.callback = callback self.context = context self.prev_view = self.screen.current_view self.screen.screen_container.alternate_view = True @@ -32,13 +33,12 @@ class WinForm(object): self.screen.switch_view(view_type=view_type, context=context) if new and not switch_new: self.screen.new(context=self.context) - self.win = gtk.Dialog(_('Link'), parent, - gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT) - self.win.set_property('default-width', 760) - self.win.set_property('default-height', 500) + self.win = gtk.Dialog(_('Link'), self.parent, + gtk.DIALOG_DESTROY_WITH_PARENT) self.win.set_position(gtk.WIN_POS_CENTER_ON_PARENT) self.win.set_icon(TRYTON_ICON) self.win.set_has_separator(False) + self.win.connect('response', self.response) self.accel_group = gtk.AccelGroup() self.win.add_accel_group(self.accel_group) @@ -190,23 +190,19 @@ class WinForm(object): scroll.add(self.screen.screen_container.alternate_viewport) - width, height = self.screen.current_view.widget.size_request() - scroll.set_size_request(width, height + 30) - parent_width, parent_height = parent.get_size() - win_width, win_height = self.win.get_size() - self.widget_width = min(parent_width - 20, max(win_width, width + 20)) - self.widget_height = min(parent_height - 60, height + win_height + 20) - self.win.set_default_size(self.widget_width, self.widget_height) + sensible_allocation = self.sensible_widget.get_allocation() + self.win.set_default_size(int(sensible_allocation.width * 0.9), + int(sensible_allocation.height * 0.9)) if view_type == 'tree': self.screen.signal_connect(self, 'record-message', self._sig_label) self.screen.screen_container.alternate_viewport.connect( 'key-press-event', self.on_keypress) + self.register() self.win.show() - self.prev_window = self.screen.window - self.screen.window = self.win + common.center_window(self.win, self.parent, self.sensible_widget) self.screen.display() self.screen.current_view.set_cursor() @@ -265,22 +261,25 @@ class WinForm(object): ids = rpc.execute('model', self.attrs['relation'], 'search', dom, 0, CONFIG['client.limit'], None, context) except TrytonServerError, exception: - common.process_exception(exception, self.window) + common.process_exception(exception) return False - if len(ids) != 1: - win = WinSearch(self.attrs['relation'], sel_multi=True, ids=ids, - context=context, domain=domain, parent=self.window, - views_preload=self.attrs.get('views', {})) - ids = win.run() - res_id = None - if ids: - res_id = ids[0] - self.screen.load(ids, modified=True) - self.screen.display(res_id=res_id) - if self.screen.current_view: - self.screen.current_view.set_cursor() - self.wid_text.set_text('') + def callback(ids): + res_id = None + if ids: + res_id = ids[0] + self.screen.load(ids, modified=True) + self.screen.display(res_id=res_id) + if self.screen.current_view: + self.screen.current_view.set_cursor() + self.wid_text.set_text('') + + if len(ids) != 1: + WinSearch(self.attrs['relation'], callback, sel_multi=True, + ids=ids, context=context, domain=domain, + views_preload=self.attrs.get('views', {})) + else: + callback(ids) def _sig_label(self, screen, signal_data): name = '_' @@ -289,30 +288,30 @@ class WinForm(object): line = '(%s/%s)' % (name, signal_data[1]) self.label.set_text(line) - def run(self): + def response(self, win, response_id): validate = False cancel_responses = (gtk.RESPONSE_CANCEL, gtk.RESPONSE_DELETE_EVENT) - while not validate: - response = self.win.run() - self.screen.current_view.set_value() - if (response in cancel_responses - or self.screen.current_record is None): - break + self.screen.current_view.set_value() + if (response_id not in cancel_responses + and self.screen.current_record is not None): validate = self.screen.current_record.validate( self.screen.current_view.get_fields()) if not validate: self.screen.current_view.set_cursor() self.screen.display() - continue - if response == gtk.RESPONSE_ACCEPT: + return + if response_id == gtk.RESPONSE_ACCEPT: self.new() - validate = False + return if (self.but_cancel and self.screen.current_record - and response in cancel_responses): + and response_id in cancel_responses): self.screen.group.remove(self.screen.current_record, remove=True) - return False - return response not in cancel_responses + result = False + else: + result = response_id not in cancel_responses + self.destroy() + self.callback(result) def new(self): self.screen.new(context=self.context) @@ -326,6 +325,12 @@ class WinForm(object): viewport.remove(viewport.get_child()) self.screen.switch_view(view_type=self.prev_view.view_type) self.screen.signal_unconnect(self) - self.screen.window = self.prev_window self.win.destroy() - self.parent.present() + NoModal.destroy(self) + + def show(self): + self.win.show() + common.center_window(self.win, self.parent, self.sensible_widget) + + def hide(self): + self.win.hide() diff --git a/tryton/gui/window/win_import.py b/tryton/gui/window/win_import.py index 2c0248870e..23838510b8 100644 --- a/tryton/gui/window/win_import.py +++ b/tryton/gui/window/win_import.py @@ -15,9 +15,10 @@ _ = gettext.gettext class WinImport(object): "Window import" - def __init__(self, model, parent): + def __init__(self, model): + self.parent = common.get_toplevel_window() self.dialog = gtk.Dialog( - title=_("Import from CSV"), parent=parent, + title=_("Import from CSV"), parent=self.parent, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT | gtk.WIN_POS_CENTER_ON_PARENT) self.dialog.set_icon(TRYTON_ICON) @@ -170,7 +171,6 @@ class WinImport(object): self.model = model self.fields_data = {} - self.parent = parent self.dialog.show_all() self.import_csv_file.set_current_folder(CONFIG['client.default_path']) @@ -360,16 +360,14 @@ class WinImport(object): return False if res[0] >= 0: if res[0] == 1: - common.message(_('%d record imported!') % (res[0],), - self.parent) + common.message(_('%d record imported!') % res[0]) else: - common.message(_('%d records imported!') % (res[0],), - self.parent) + common.message(_('%d records imported!') % res[0]) else: buf = '' for key, val in res[1].items(): buf += ('\t%s: %s\n' % (str(key), str(val))) - common.error(_('Importation Error!'), self.parent, + common.error(_('Importation Error!'), _('Error trying to import this record:\n' \ '%s\nError Message:\n%s\n\n%s') % (buf, res[2], res[3])) return True diff --git a/tryton/gui/window/win_search.py b/tryton/gui/window/win_search.py index e689ec127a..68953e7ccf 100644 --- a/tryton/gui/window/win_search.py +++ b/tryton/gui/window/win_search.py @@ -6,28 +6,30 @@ import tryton.rpc as rpc from tryton.gui.window.view_form.screen import Screen import tryton.gui.window.view_form.widget_search as widget_search from tryton.config import TRYTON_ICON -import tryton.common as common from tryton.gui.window.win_form import WinForm +from tryton.gui.window.nomodal import NoModal _ = gettext.gettext -class WinSearch(object): +class WinSearch(NoModal): - def __init__(self, model, sel_multi=True, ids=None, context=None, - domain=None, parent=None, views_preload=None): + def __init__(self, model, callback, sel_multi=True, ids=None, context=None, + domain=None, views_preload=None): + NoModal.__init__(self) if views_preload is None: views_preload = {} self.domain = domain or [] self.context = context or {} self.sel_multi = sel_multi - self.parent = parent + self.callback = callback self.win = gtk.Dialog(_('Search'), self.parent, - gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT) + gtk.DIALOG_DESTROY_WITH_PARENT) self.win.set_icon(TRYTON_ICON) self.win.set_has_separator(True) self.win.set_default_response(gtk.RESPONSE_APPLY) + self.win.connect('response', self.response) self.accel_group = gtk.AccelGroup() self.win.add_accel_group(self.accel_group) @@ -47,9 +49,9 @@ class WinSearch(object): scrollwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.win.vbox.pack_start(scrollwindow, expand=True, fill=True) - self.screen = Screen(model, self.win, domain=domain, - mode=['tree'], context=context, - views_preload=views_preload, row_activate=self.sig_activate) + self.screen = Screen(model, domain=domain, mode=['tree'], + context=context, views_preload=views_preload, + row_activate=self.sig_activate) self.view = self.screen.current_view self.view.unset_editable() sel = self.view.widget_tree.get_selection() @@ -74,6 +76,9 @@ class WinSearch(object): self.win.set_size_request(700, 500) + self.register() + self.win.show() + def sig_activate(self, *args): self.view.widget_tree.emit_stop_by_name('row_activated') if not self.sel_multi: @@ -86,33 +91,34 @@ class WinSearch(object): return False def destroy(self): - self.parent.present() self.screen.destroy() self.win.destroy() + NoModal.destroy(self) - def run(self): - end = False - while not end: - button = self.win.run() - if button == gtk.RESPONSE_OK: + def show(self): + self.win.show() + + def hide(self): + self.win.hide() + + def response(self, win, response_id): + res = None + if response_id == gtk.RESPONSE_OK: + res = self.screen.sel_ids_get() + elif response_id == gtk.RESPONSE_APPLY: + if not self.screen.search_filter(): res = self.screen.sel_ids_get() - end = True - elif button == gtk.RESPONSE_APPLY: - end = not self.screen.search_filter() - if end: - res = self.screen.sel_ids_get() - elif button == gtk.RESPONSE_ACCEPT: - res = None - screen = Screen(self.model_name, self.win, domain=self.domain, - context=self.context, mode=['form']) - win = WinForm(screen, self.win, new=True) - if win.run(): - if screen.save_current(): - res = [screen.current_record.id] - win.destroy() - end = True else: - res = None - end = True + return + elif response_id == gtk.RESPONSE_ACCEPT: + screen = Screen(self.model_name, domain=self.domain, + context=self.context, mode=['form']) + def callback(result): + if result and screen.save_current(): + res = [screen.current_record.id] + self.destroy() + self.callback(res) + WinForm(screen, callback, new=True) + return self.destroy() - return res + return self.callback(res) diff --git a/tryton/gui/window/window.py b/tryton/gui/window/window.py index 07f0f22ae7..80b3f4f84d 100644 --- a/tryton/gui/window/window.py +++ b/tryton/gui/window/window.py @@ -21,7 +21,7 @@ class Window(object): Window.allow_similar = True @staticmethod - def create(view_ids, model, res_id=False, domain=None, window=None, + def create(view_ids, model, res_id=False, domain=None, context=None, mode=None, name=False, limit=None, auto_refresh=False, search_value=None, icon=None): from tryton.gui import Main @@ -30,26 +30,29 @@ class Window(object): if model: from form import Form - win = Form(model, window, res_id, domain, mode=mode, - view_ids=(view_ids or []), context=context, name=name, - limit=limit, auto_refresh=auto_refresh, - search_value=search_value) + win = Form(model, res_id, domain, mode=mode, + view_ids=(view_ids or []), context=context, name=name, + limit=limit, auto_refresh=auto_refresh, + search_value=search_value) else: from board import Board - win = Board(model, window, view_ids and view_ids[0] or None, - context=context, name=name, auto_refresh=auto_refresh) + win = Board(model, view_ids and view_ids[0] or None, + context=context, name=name, auto_refresh=auto_refresh) win.icon = icon Main.get_main().win_add(win, hide_current=Window.hide_current, allow_similar=Window.allow_similar) @staticmethod - def create_wizard(action, datas, parent, state='init', direct_print=False, - email_print=False, email=None, name=False, context=None, - icon=None): + def create_wizard(action, data, state='init', direct_print=False, + email_print=False, email=None, name=False, context=None, icon=None, + window=False): from tryton.gui import Main - from wizard import Wizard - win = Wizard(parent, name=name) - win.icon = icon - Main.get_main().win_add(win, Window.hide_current) - win.run(action, datas, state=state, direct_print=direct_print, + from wizard import WizardForm, WizardDialog + if window: + win = WizardForm(name=name) + win.icon = icon + Main.get_main().win_add(win, Window.hide_current) + else: + win = WizardDialog(name=name) + win.run(action, data, state=state, direct_print=direct_print, email_print=email_print, email=email, context=context) diff --git a/tryton/gui/window/wizard.py b/tryton/gui/window/wizard.py index 85552d29f4..e2c0583bec 100644 --- a/tryton/gui/window/wizard.py +++ b/tryton/gui/window/wizard.py @@ -2,23 +2,24 @@ #this repository contains the full copyright notices and license terms. import gtk import pango +import gettext from tryton.signal_event import SignalEvent import tryton.rpc as rpc import tryton.common as common from tryton.gui.window.view_form.screen import Screen from tryton.gui import Main from tryton.exceptions import TrytonServerError +from tryton.config import CONFIG +from tryton.gui.window.nomodal import NoModal +_ = gettext.gettext -class Wizard(SignalEvent): - "Wizard" +class Wizard(object): - def __init__(self, window, name=False): + def __init__(self, name=False): super(Wizard, self).__init__() - self.window = window self.widget = gtk.VBox(spacing=3) - self.toolbar_box = gtk.HBox() - self.widget.pack_start(self.toolbar_box, False, True) + self.toolbar_box = None self.widget.show() self.name = name or '' self.model = '' @@ -30,15 +31,8 @@ class Wizard(SignalEvent): self.email = False self.context = None self.states = {} - - self.handlers = { - 'but_close': self.sig_close - } - - def sig_close(self): - if 'end' in self.states: - self.states['end'].clicked() - return self.state == 'end' + self.response2state = {} + self.__processing = False def run(self, action, datas, state='init', direct_print=False, email_print=False, email=None, context=None): @@ -55,7 +49,7 @@ class Wizard(SignalEvent): try: self.wiz_id = rpc.execute(*args) except TrytonServerError, exception: - self.wiz_id = common.process_exception(exception, self.window, *args) + self.wiz_id = common.process_exception(exception, *args) if not self.wiz_id: return self.process() @@ -63,66 +57,72 @@ class Wizard(SignalEvent): def process(self): from tryton.action import Action res = {} - while self.state != 'end': - ctx = self.context.copy() - ctx.update(rpc.CONTEXT) - ctx['active_id'] = self.datas.get('id') - ctx['active_ids'] = self.datas.get('ids') - rpcprogress = common.RPCProgress('execute', ('wizard', - self.action, 'execute', self.wiz_id, self.datas, self.state, ctx), - self.window) - try: - res = rpcprogress.run() - except TrytonServerError, exception: - common.process_exception(exception, self.window) - break - if not res: - self.end() - return - self.clean() - - if 'datas' in res: - self.datas['form'] = res['datas'] - elif res['type'] == 'form': - self.datas['form'] = {} - if res['type'] == 'form': - self.update(res, res['state'], res['object'], context=ctx) - self.screen.current_record.set_default(self.datas['form']) - break - elif res['type'] == 'action': - self.state = res['state'] - if self.state == 'end': + if self.__processing: + return + try: + self.__processing = True + while self.state != 'end': + ctx = self.context.copy() + ctx.update(rpc.CONTEXT) + ctx['active_id'] = self.datas.get('id') + ctx['active_ids'] = self.datas.get('ids') + rpcprogress = common.RPCProgress('execute', ('wizard', + self.action, 'execute', self.wiz_id, self.datas, + self.state, ctx)) + try: + res = rpcprogress.run() + except TrytonServerError, exception: + common.process_exception(exception) + self.end() + break + if not res: self.end() - Action._exec_action(res['action'], self.window, self.datas, - context=ctx) - if self.state == 'end': return - elif res['type'] == 'print': - self.datas['report_id'] = res.get('report_id', False) - if res.get('get_id_from_action', False): - backup_ids = datas['ids'] - self.datas['ids'] = self.datas['form']['ids'] - Action.exec_report(res['report'], self.datas, self.window, - direct_print=self.direct_print, - email_print=self.email_print, email=self.email, - context=ctx) - self.datas['ids'] = backup_ids - else: - Action.exec_report(res['report'], self.datas, self.window, - direct_print=self.direct_print, - email_print=self.email_print, email=self.email, - context=ctx) - self.state = res['state'] - elif res['type'] == 'state': - self.state = res['state'] - if self.state == 'end': - self.end() + if 'datas' in res: + self.datas['form'] = res['datas'] + elif res['type'] == 'form': + self.datas['form'] = {} + if res['type'] == 'form': + self.clean() + self.update(res, res['state'], res['object'], context=ctx) + self.screen.current_record.set_default(self.datas['form']) + break + elif res['type'] == 'action': + self.state = res['state'] + sensitive_widget = self.widget.get_toplevel() + if self.state == 'end': + self.end() + Action._exec_action(res['action'], self.datas, context=ctx) + if self.state == 'end' or ( + res['action']['type'] == 'ir.action.wizard' + and not sensitive_widget.props.sensitive): + return + elif res['type'] == 'print': + self.datas['report_id'] = res.get('report_id', False) + if res.get('get_id_from_action', False): + backup_ids = datas['ids'] + self.datas['ids'] = self.datas['form']['ids'] + Action.exec_report(res['report'], self.datas, + direct_print=self.direct_print, + email_print=self.email_print, email=self.email, + context=ctx) + self.datas['ids'] = backup_ids + else: + Action.exec_report(res['report'], self.datas, + direct_print=self.direct_print, + email_print=self.email_print, email=self.email, + context=ctx) + self.state = res['state'] + elif res['type'] == 'state': + self.state = res['state'] + + if self.state == 'end': + self.end() + finally: + self.__processing = False def destroy(self): - if self.toolbar_box.get_children(): - toolbar = self.toolbar_box.get_children()[0] - self.toolbar_box.remove(toolbar) if hasattr(self, 'screen'): self.screen.signal_unconnect(self) self.screen.destroy() @@ -137,14 +137,14 @@ class Wizard(SignalEvent): rpc.context_reload() except TrytonServerError: pass - Main.get_main()._win_del(self.widget) def clean(self): for widget in self.widget.get_children(): self.widget.remove(widget) self.states = {} - def sig_clicked(self, widget, state): + def response(self, widget, response): + state = self.response2state.get(response, 'end') self.screen.current_view.set_value() if not self.screen.current_record.validate() \ and state != 'end': @@ -154,26 +154,26 @@ class Wizard(SignalEvent): self.state = state self.process() - def update(self, view, state, obj_name, context=None): + def _get_button(self, state): + button = gtk.Button() + button.set_use_underline(True) + button.set_label('_' + state[1]) + if len(state) >= 3: + common.ICONFACTORY.register_icon(state[2]) + icon = gtk.Image() + icon.set_from_stock(state[2], gtk.ICON_SIZE_BUTTON) + button.set_image(icon) + self.states[state[0]] = button + response = len(self.states) + self.response2state[response] = state[0] + button.show() + return button + + def update(self, view, states, obj_name, context=None): self.model = obj_name - hbuttonbox = gtk.HButtonBox() - hbuttonbox.set_spacing(5) - hbuttonbox.set_layout(gtk.BUTTONBOX_END) - hbuttonbox.show() - for i in state: - but = gtk.Button() - but.set_use_underline(True) - but.set_label('_' + i[1]) - but.show() - but.connect('clicked', self.sig_clicked, i[0]) - self.states[i[0]] = but - if len(i) >= 3: - common.ICONFACTORY.register_icon(i[2]) - icon = gtk.Image() - icon.set_from_stock(i[2], gtk.ICON_SIZE_BUTTON) - but.set_image(icon) - hbuttonbox.pack_start(but) + for state in states: + self._get_button(state) val = {} fields = view['fields'] @@ -181,7 +181,7 @@ class Wizard(SignalEvent): if 'value' in fields[i]: val[i] = fields[i]['value'] - self.screen = Screen(obj_name, self.window, mode=[], context=context) + self.screen = Screen(obj_name, mode=[], context=context) self.screen.add_view(view, display=True) self.screen.widget.show() @@ -224,7 +224,8 @@ class Wizard(SignalEvent): self.widget.pack_start(eb, expand=False, fill=True, padding=3) - self.widget.pack_start(self.toolbar_box, False, True) + if self.toolbar_box: + self.widget.pack_start(self.toolbar_box, False, True) viewport = gtk.Viewport() viewport.set_shadow_type(gtk.SHADOW_NONE) @@ -239,8 +240,135 @@ class Wizard(SignalEvent): self.widget.pack_start(self.scrolledwindow) - self.widget.pack_start(hbuttonbox, expand=False, fill=True) - self.screen.new(default=False) self.screen.current_record.set_default(val) self.screen.current_view.set_cursor() + + +class WizardForm(Wizard,SignalEvent): + "Wizard" + + def __init__(self, name=False): + super(WizardForm, self).__init__(name=name) + self.toolbar_box = gtk.HBox() + self.hbuttonbox = gtk.HButtonBox() + self.hbuttonbox.set_spacing(5) + self.hbuttonbox.set_layout(gtk.BUTTONBOX_END) + self.hbuttonbox.show() + self.widget.pack_start(self.toolbar_box, False, True) + self.dialogs = [] + + self.handlers = { + 'but_close': self.sig_close + } + + def clean(self): + super(WizardForm, self).clean() + for button in self.hbuttonbox.get_children(): + self.hbuttonbox.remove(button) + + def _get_button(self, state): + button = super(WizardForm, self)._get_button(state) + button.connect('clicked', self.response, state[0]) + self.hbuttonbox.pack_start(button) + return button + + def update(self, view, states, obj_name, context=None): + super(WizardForm, self).update(view, states, obj_name, context=context) + self.widget.pack_start(self.hbuttonbox, expand=False, fill=True) + + def sig_close(self): + if 'end' in self.states: + self.states['end'].clicked() + return self.state == 'end' + + def destroy(self): + if self.toolbar_box.get_children(): + toolbar = self.toolbar_box.get_children()[0] + self.toolbar_box.remove(toolbar) + super(WizardForm, self).destroy() + + def end(self): + super(WizardForm, self).end() + Main.get_main()._win_del(self.widget) + + +class WizardDialog(Wizard, NoModal): + + def __init__(self, name=False): + if not name: + name = _('Wizard') + Wizard.__init__(self, name=name) + NoModal.__init__(self) + self.dia = gtk.Dialog(self.name, self.parent, + gtk.DIALOG_DESTROY_WITH_PARENT) + self.dia.set_position(gtk.WIN_POS_CENTER_ON_PARENT) + if hasattr(self.dia, 'set_deletable'): + self.dia.set_deletable(False) + self.dia.connect('close', self.close) + self.dia.connect('response', self.response) + self.dia.connect('state-changed', self.state_changed) + + self.accel_group = gtk.AccelGroup() + self.dia.add_accel_group(self.accel_group) + + self.dia.vbox.add(self.widget) + + self.register() + + def clean(self): + super(WizardDialog, self).clean() + hbuttonbox = self.dia.get_action_area() + for button in hbuttonbox.get_children(): + hbuttonbox.remove(button) + + def _get_button(self, state): + button = super(WizardDialog, self)._get_button(state) + response = len(self.states) + self.dia.add_action_widget(button, response) + if len(state) >= 4 and state[3]: + button.set_flags(gtk.CAN_DEFAULT) + button.add_accelerator('clicked', self.accel_group, + gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, + gtk.ACCEL_VISIBLE) + self.dia.set_default_response(response) + return button + + def update(self, view, states, obj_name, context=None): + super(WizardDialog, self).update(view, states, obj_name, context=context) + sensible_allocation = self.sensible_widget.get_allocation() + self.dia.set_default_size(int(sensible_allocation.width * 0.9), + int(sensible_allocation.height * 0.9)) + self.dia.show() + common.center_window(self.dia, self.parent, self.sensible_widget) + + def destroy(self): + self.dia.destroy() + NoModal.destroy(self) + main = Main.get_main() + if self.parent == main.window: + current_form = main.get_page() + if current_form: + for dialog in current_form.dialogs: + dialog.show() + if hasattr(self.page, 'screen'): + self.page.screen.reload(written=True) + super(WizardDialog, self).destroy() + + def end(self): + super(WizardDialog, self).end() + self.destroy() + + def close(self, widget, event=None): + widget.emit_stop_by_name('close') + return True + + def show(self): + self.dia.show() + + def hide(self): + self.dia.hide() + + def state_changed(self, widget, state): + if self.dia.props.sensitive and state == gtk.STATE_INSENSITIVE: + self.process() diff --git a/tryton/plugins/__init__.py b/tryton/plugins/__init__.py index c9f7b11983..119eca5e7b 100644 --- a/tryton/plugins/__init__.py +++ b/tryton/plugins/__init__.py @@ -26,16 +26,16 @@ if os.path.isdir(PLUGINS_PATH): except ImportError, exception: continue -def execute(datas, parent): +def execute(datas): result = {} for module in MODULES: for name, func in module.get_plugins(datas['model']): result[name] = func if not result: - common.message(_('No available plugin for this resource!'), parent) + common.message(_('No available plugin for this resource!')) return False - res = common.selection(_('Choose a Plugin'), result, parent, alwaysask=True) + res = common.selection(_('Choose a Plugin'), result, alwaysask=True) if res: - res[1](datas, parent) + res[1](datas) return True diff --git a/tryton/plugins/translation/__init__.py b/tryton/plugins/translation/__init__.py index 0e906d2b8a..b21b318577 100644 --- a/tryton/plugins/translation/__init__.py +++ b/tryton/plugins/translation/__init__.py @@ -5,11 +5,11 @@ import gettext _ = gettext.gettext -def translate_view(datas, parent): +def translate_view(datas): model = datas['model'] Window.create(False, 'ir.translation', res_id=False, domain=[('model', '=', model)], - mode=['tree', 'form'], window=parent) + mode=['tree', 'form']) def get_plugins(model): return [ diff --git a/tryton/plugins/workflow/__init__.py b/tryton/plugins/workflow/__init__.py index 9b88d79739..502e5d4c16 100644 --- a/tryton/plugins/workflow/__init__.py +++ b/tryton/plugins/workflow/__init__.py @@ -5,16 +5,16 @@ import gettext _ = gettext.gettext -def workflow_print(datas, parent): +def workflow_print(datas): datas = datas.copy() datas['nested'] = False - Action.exec_report('workflow.instance.graph', datas, parent) + Action.exec_report('workflow.instance.graph', datas) return True -def workflow_print_complex(datas, parent): +def workflow_print_complex(datas): datas = datas.copy() datas['nested'] = True - Action.exec_report('workflow.instance.graph', datas, parent) + Action.exec_report('workflow.instance.graph', datas) return True def get_plugins(model): diff --git a/tryton/wizard/__init__.py b/tryton/wizard/__init__.py deleted file mode 100644 index 5115afa69e..0000000000 --- a/tryton/wizard/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -#This file is part of Tryton. The COPYRIGHT file at the top level of -#this repository contains the full copyright notices and license terms. -from main import * diff --git a/tryton/wizard/main.py b/tryton/wizard/main.py deleted file mode 100644 index 323dbe41b9..0000000000 --- a/tryton/wizard/main.py +++ /dev/null @@ -1,262 +0,0 @@ -#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 -from tryton.config import CONFIG -from tryton.exceptions import TrytonServerError - -_ = gettext.gettext - - -class Dialog(object): - "Dialog for wizard" - - def __init__(self, view, state, obj_name, parent, - action='', size=(0, 0), context=None): - self.parent = parent - self.action = action - self.states = [] - default = -1 - self.dia = gtk.Dialog(_('Wizard'), parent, - gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) - self.dia.set_position(gtk.WIN_POS_CENTER_ON_PARENT) - if hasattr(self.dia, 'set_deletable'): - self.dia.set_deletable(False) - self.dia.connect('close', self.close) - - 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: - common.ICONFACTORY.register_icon(i[2]) - 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 = {} - fields = view['fields'] - for i in fields: - if 'value' in fields[i]: - val[i] = fields[i]['value'] - - self.screen = Screen(obj_name, self.dia, mode=[], context=context) - self.screen.add_view(view, display=True) - - title = gtk.Label() - title.set_use_markup(True) - title.modify_font(pango.FontDescription("14")) - title.set_label('' + self.screen.current_view.title + '') - 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() - dia_width, dia_height = self.dia.get_size() - self.widget_width = min(parent_width - 20, - max(dia_width, width + 20, size[0])) - self.widget_height = min(parent_height - 60, - max(height + dia_height + 20, size[1])) - self.dia.set_default_size(self.widget_width, - self.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_record.set_default(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_record.validate() \ - or (res<0) or (self.states[res]=='end'): - break - self.screen.display() - - if CONFIG['client.save_width_height']: - width, height = self.dia.get_size() - if (width, height) != (self.widget_width, self.widget_height): - try: - rpc.execute('model', 'ir.action.wizard_size', 'set_size', - self.action, self.screen.model_name, width, height, - rpc.CONTEXT) - except TrytonServerError: - pass - - 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 close(self, widget, event=None): - widget.emit_stop_by_name('close') - return True - - 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', - direct_print=False, email_print=False, email=None, - context=None): - from tryton.action import Action - if not 'form' in datas: - datas['form'] = {} - args = ('wizard', action, 'create', rpc.CONTEXT) - try: - wiz_id = rpc.execute(*args) - except TrytonServerError, exception: - wiz_id = common.process_exception(exception, parent, *args) - if not wiz_id: - return - dia = None - res = {} - while state != 'end': - ctx = context.copy() - ctx.update(rpc.CONTEXT) - ctx['active_id'] = datas.get('id') - ctx['active_ids'] = datas.get('ids') - rpcprogress = common.RPCProgress('execute', ('wizard', - action, 'execute', wiz_id, datas, state, ctx), parent) - try: - res = rpcprogress.run() - exception = None - except TrytonServerError, exception: - if common.process_exception(exception, parent): - continue - else: - # Continue by running previous result except if access to - # wizard is denied - if exception.args[0] == 'AccessDenied': - break - if not res: - if dia: - res = {'type': 'form'} - else: - break - else: - if dia and not exception: - 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, res['state'], res['object'], parent, - action=action, size=res['size'], context=ctx) - dia.screen.current_record.set_default(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, - direct_print=direct_print, email_print=email_print, - email=email, context=ctx) - datas['ids'] = backup_ids - else: - Action.exec_report(res['report'], datas, dia or parent, - direct_print=direct_print, email_print=email_print, - email=email, context=ctx) - state = res['state'] - elif res['type'] == 'state': - state = res['state'] - if dia: - dia.destroy() - dia = None - try: - rpc.execute('wizard', action, 'delete', wiz_id, rpc.CONTEXT) - #XXX to remove when company displayed in status bar - rpc.context_reload() - except TrytonServerError: - pass