nch(OpenERP) has proposed merging 
lp:~openerp-commiter/openobject-client/asynchronous_rpccall into 
lp:openobject-client.

Requested reviews:
  OpenERP sa GTK client R&D (openerp-dev-gtk)


Display progressbar for long rpc calls, set window's cursor to watch from arrow 
when there is small rpc calls to the server.
-- 
https://code.launchpad.net/~openerp-commiter/openobject-client/asynchronous_rpccall/+merge/39831
Your team OpenERP sa GTK client R&D is requested to review the proposed merge 
of lp:~openerp-commiter/openobject-client/asynchronous_rpccall into 
lp:openobject-client.
=== modified file 'bin/common/common.py'
--- bin/common/common.py	2010-10-27 11:58:25 +0000
+++ bin/common/common.py	2010-11-02 09:51:44 +0000
@@ -167,6 +167,19 @@
     win.show_all()
     return win, pb
 
+def set_busy_cursor():
+    root = gtk.gdk.screen_get_default()
+    cursor_win = root.get_active_window()
+    if cursor_win:
+        cursor_win.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
+    gtk.main_iteration(False)
+    return cursor_win
+
+def reset_busy_cursor(cursor_win=None):
+    if cursor_win:
+        cursor_win.set_cursor(None)
+    gtk.main_iteration()
+
 def _search_file(file, dir='path.share'):
     tests = [
         lambda x: os.path.join(os.getcwd(), os.path.dirname(sys.argv[0]), x),

=== modified file 'bin/modules/gui/window/tree.py'
--- bin/modules/gui/window/tree.py	2010-09-27 05:55:25 +0000
+++ bin/modules/gui/window/tree.py	2010-11-02 09:51:44 +0000
@@ -186,23 +186,27 @@
         self.sig_action(keyword='client_print_multi')
 
     def sig_action(self, widget=None, keyword='tree_but_action', id=None, report_type='pdf', warning=True):
-        ids = self.ids_get()
-
-        if not id and ids and len(ids):
-            id = ids[0]
-        if id:
-            ctx = self.context.copy()
-            if 'active_ids' in ctx:
-                del ctx['active_ids']
-            if 'active_id' in ctx:
-                del ctx['active_id']
-            obj = service.LocalService('action.main')
-            return obj.exec_keyword(keyword, {'model':self.model, 'id':id,
-                'ids':ids, 'report_type':report_type, 'window': self.window}, context=ctx,
-                warning=warning)
-        else:
-            common.message(_('No resource selected!'))
-        return False
+        cursor = common.set_busy_cursor()
+        try:
+            res = False
+            ids = self.ids_get()
+            if not id and ids and len(ids):
+                id = ids[0]
+            if id:
+                ctx = self.context.copy()
+                if 'active_ids' in ctx:
+                    del ctx['active_ids']
+                if 'active_id' in ctx:
+                    del ctx['active_id']
+                obj = service.LocalService('action.main')
+                res = obj.exec_keyword(keyword, {'model':self.model, 'id':id,
+                      'ids':ids, 'report_type':report_type, 'window': self.window}, context=ctx,
+                      warning=warning)
+            else:
+                common.message(_('No resource selected!'))
+        finally:
+            common.reset_busy_cursor(cursor)
+            return res
 
     def sig_open(self, widget, iter, path):
         if not self.sig_action(widget, 'tree_but_open', warning=False):

=== modified file 'bin/rpc.py'
--- bin/rpc.py	2010-10-13 10:44:15 +0000
+++ bin/rpc.py	2010-11-02 09:51:44 +0000
@@ -29,7 +29,8 @@
 import common
 import options
 import os
-
+import thread
+import time
 import re
 
 CONCURRENCY_CHECK_FIELD = '__last_update'
@@ -68,23 +69,52 @@
 
 
 class gw_inter(object):
-    __slots__ = ('_url', '_db', '_uid', '_passwd', '_sock', '_obj')
+    __slots__ = ('_url', '_db', '_uid', '_passwd', '_sock', '_obj','thread_loop','res','exception')
     def __init__(self, url, db, uid, passwd, obj='/object'):
         self._url = url
         self._db = db
         self._uid = uid
         self._obj = obj
         self._passwd = passwd
+        self.thread_loop = False
+        self.exception = None
+        self.res = None
+
     def exec_auth(method, *args):
         pass
+
     def execute(method, *args):
         pass
 
+    def raise_exception(self, exception):
+        if isinstance(exception, socket.error):
+            common.message(_('Unable to reach to OpenERP server !\nYou should check your connection to the network and the OpenERP server.'), _('Connection Error'), type=gtk.MESSAGE_ERROR)
+            raise rpc_exception(69, 'Connection refused!')
+        else:
+            if isinstance(exception, xmlrpclib.Fault) \
+                    or isinstance(exception, tiny_socket.Myexception):
+                a = rpc_exception(exception.faultCode, exception.faultString)
+                if a.type in ('warning','UserError'):
+                    if a.message in ('ConcurrencyException') and len(args) > 4:
+                        if common.concurrency(args[0], args[2][0], args[4]):
+                            if CONCURRENCY_CHECK_FIELD in args[4]:
+                                del args[4][CONCURRENCY_CHECK_FIELD]
+                            return self.rpc_exec_auth(obj, method, *args)
+                    else:
+                        common.warning(a.data, a.message)
+                else:
+                    common.error(_('Application Error'), exception.faultCode, exception.faultString)
+            else:
+                common.error(_('Application Error'), _('View details'), str(exception))
+            raise exception
+
+
 class xmlrpc_gw(gw_inter):
     __slots__ = ('_url', '_db', '_uid', '_passwd', '_sock', '_obj')
     def __init__(self, url, db, uid, passwd, obj='/object'):
         gw_inter.__init__(self, url, db, uid, passwd, obj)
         self._sock = xmlrpclib.ServerProxy(url+obj)
+
     def exec_auth(self, method, *args):
         logging.getLogger('rpc.request').debug_rpc(str((method, self._db, self._uid, '*', args)))
         res = self.execute(method, self._uid, self._passwd, *args)
@@ -105,8 +135,38 @@
             return result
 
     def execute(self, method, *args):
-        result = getattr(self._sock,method)(self._db, *args)
-        return self.__convert(result)
+        self.thread_loop = False
+        self.exception = None
+
+        def execute_call(method, args):
+            try:
+                self.res = getattr(self._sock,method)(self._db, *args)
+                self.res = self.__convert(self.res)
+            except Exception, e:
+                self.exception = e
+            self.thread_loop = True
+            return True
+
+        thread.start_new_thread(execute_call, (method, args))
+        counter = 0
+        win = None
+        progressbar = None
+        while not self.thread_loop:
+            time.sleep(0.01)
+            counter += 1
+            if counter == 100:
+                if not win or not progressbar:
+                    win, progressbar = common.OpenERP_Progressbar()
+            if progressbar and (counter % 10) == 0:
+                progressbar.pulse()
+            if win:
+                gtk.main_iteration(False)
+        if win:
+            win.destroy()
+            gtk.main_iteration()
+        if self.exception:
+            self.raise_exception(self.exception)
+        return self.res
 
 class tinySocket_gw(gw_inter):
     __slots__ = ('_url', '_db', '_uid', '_passwd', '_sock', '_obj')
@@ -114,26 +174,53 @@
         gw_inter.__init__(self, url, db, uid, passwd, obj)
         self._sock = tiny_socket.mysocket()
         self._obj = obj[1:]
+
     def exec_auth(self, method, *args):
         logging.getLogger('rpc.request').debug_rpc(str((method, self._db, self._uid, '*', args)))
         res = self.execute(method, self._uid, self._passwd, *args)
         logging.getLogger('rpc.result').debug_rpc_answer(str(res))
         return res
+
     def execute(self, method, *args):
-        self._sock.connect(self._url)
-        try:
-            self._sock.mysend((self._obj, method, self._db)+args)
-            res = self._sock.myreceive()
-            self._sock.disconnect()
-            return res
-        except Exception,e:
+        self.thread_loop = False
+        self.exception = None
+
+        def execute_call(method, args):
+            self._sock.connect(self._url)
             try:
+                self._sock.mysend((self._obj, method, self._db)+args)
+                self.res = self._sock.myreceive()
                 self._sock.disconnect()
-            except Exception:
-                pass
-            # make sure we keep the exception context, even
-            # if disconnect() raised above.
-            raise e
+            except Exception, e:
+                try:
+                    self._sock.disconnect()
+                except Exception:
+                    pass
+                self.exception = e
+            self.thread_loop = True
+            return True
+
+        thread.start_new_thread(execute_call, (method, args))
+        counter = 0
+        win = None
+        progressbar = None
+        while not self.thread_loop:
+            time.sleep(0.01)
+            counter += 1
+            if counter == 100:
+                if not win or not progressbar:
+                    win, progressbar = common.OpenERP_Progressbar()
+            if progressbar and (counter % 10) == 0:
+                progressbar.pulse()
+            if win:
+                gtk.main_iteration(False)
+        if win:
+            win.destroy()
+            gtk.main_iteration()
+        if self.exception:
+            self.raise_exception(self.exception)
+        return self.res
+
 
 class rpc_session(object):
     __slots__ = ('_open', '_url', 'uid', 'uname', '_passwd', '_gw', 'db', 'context', 'timezone')
@@ -149,14 +236,8 @@
         self.timezone = 'utc'
 
     def rpc_exec(self, obj, method, *args):
-        try:
             sock = self._gw(self._url, self.db, self.uid, self._passwd, obj)
             return sock.execute(method, *args)
-        except socket.error, e:
-            common.message(str(e), title=_('Connection refused !'), type=gtk.MESSAGE_ERROR)
-            raise rpc_exception(69, _('Connection refused!'))
-        except xmlrpclib.Fault, err:
-            raise rpc_exception(err.faultCode, err.faultString)
 
     def rpc_exec_auth_try(self, obj, method, *args):
         if self._open:
@@ -166,44 +247,13 @@
             raise rpc_exception(1, 'not logged')
 
     def rpc_exec_auth_wo(self, obj, method, *args):
-        try:
-            sock = self._gw(self._url, self.db, self.uid, self._passwd, obj)
-            return sock.exec_auth(method, *args)
-        except xmlrpclib.Fault, err:
-            a = rpc_exception(err.faultCode, err.faultString)
-        except tiny_socket.Myexception, err:
-            a = rpc_exception(err.faultCode, err.faultString)
-        if a.code in ('warning', 'UserError'):
-            common.warning(a.data, a.message)
-            return None
-        raise a
+        sock = self._gw(self._url, self.db, self.uid, self._passwd, obj)
+        return sock.exec_auth(method, *args)
 
     def rpc_exec_auth(self, obj, method, *args):
         if self._open:
-            try:
-                sock = self._gw(self._url, self.db, self.uid, self._passwd, obj)
-                return sock.exec_auth(method, *args)
-            except socket.error, e:
-                common.message(_('Unable to reach to OpenERP server !\nYou should check your connection to the network and the OpenERP server.'), _('Connection Error'), type=gtk.MESSAGE_ERROR)
-                raise rpc_exception(69, 'Connection refused!')
-            except Exception, e:
-                if isinstance(e, xmlrpclib.Fault) \
-                        or isinstance(e, tiny_socket.Myexception):
-                    a = rpc_exception(e.faultCode, e.faultString)
-                    if a.type in ('warning','UserError'):
-                        if a.message in ('ConcurrencyException') and len(args) > 4:
-                            if common.concurrency(args[0], args[2][0], args[4]):
-                                if CONCURRENCY_CHECK_FIELD in args[4]:
-                                    del args[4][CONCURRENCY_CHECK_FIELD]
-                                return self.rpc_exec_auth(obj, method, *args)
-                        else:
-                            common.warning(a.data, a.message)
-                    else:
-                        common.error(_('Application Error'), e.faultCode, e.faultString)
-                else:
-                    common.error(_('Application Error'), _('View details'), str(e))
-                #TODO Must propagate the exception?
-                raise
+            sock = self._gw(self._url, self.db, self.uid, self._passwd, obj)
+            return sock.exec_auth(method, *args)
         else:
             raise rpc_exception(1, 'not logged')
 

=== modified file 'bin/widget/model/record.py'
--- bin/widget/model/record.py	2010-10-27 10:00:15 +0000
+++ bin/widget/model/record.py	2010-11-02 09:51:44 +0000
@@ -342,55 +342,61 @@
         id     : Id of the record for which the button is clicked
         attrs  : Button Attributes
         """
-        if not id:
-            id = self.id
-        if not attrs.get('confirm', False) or common.sur(attrs['confirm']):
-            button_type = attrs.get('type', 'workflow')
-            obj = service.LocalService('action.main')
-
-            if button_type == 'workflow':
-                result = rpc.session.rpc_exec_auth('/object', 'exec_workflow',
-                                                   self.resource, attrs['name'], self.id)
-                if type(result)==type({}):
-                    if result['type']== 'ir.actions.act_window_close':
-                        screen.window.destroy()
+        cursor =  common.set_busy_cursor()
+        reload = True
+        reset = False
+        try:
+            if not id:
+                id = self.id
+            if not attrs.get('confirm') or common.sur(attrs['confirm']):
+                button_type = attrs.get('type', 'workflow')
+                obj = service.LocalService('action.main')
+                if button_type == 'workflow':
+                    result = rpc.session.rpc_exec_auth('/object', 'exec_workflow',
+                                                       self.resource, attrs['name'], self.id)
+                    if isinstance(result, dict):
+                        if result['type'] == 'ir.actions.act_window_close':
+                            screen.window.destroy()
+                        else:
+                            datas = {'ids':[id], 'id':id}
+                            obj._exec_action(result, datas)
+                    elif isinstance(result, list):
+                        datas = {'ids':[id]}
+                        for rs in result:
+                            obj._exec_action(rs, datas)
+                elif button_type == 'object':
+                    if self.id:
+                        context = self.context_get()
+                        if 'context' in attrs:
+                            context.update(self.expr_eval(attrs['context'], check_load=False))
+                        result = rpc.session.rpc_exec_auth('/object', 'execute',
+                                                           self.resource,attrs['name'], [id], context)
+                        if isinstance(result, dict):
+                            if not result.get('nodestroy', False):
+                                screen.window.destroy()
+                            if result.get('type') in ('ir.actions.report.xml','ir.actions.report.custom'):
+                                common.reset_busy_cursor(cursor)
+                                reset = True
+                            obj._exec_action(result, {}, context=context)
                     else:
-                        datas = {'ids':[id], 'id':id}
-                        obj._exec_action(result, datas)
-                elif type([]) == type(result):
-                    datas = {'ids':[id]}
-                    for rs in result:
-                        obj._exec_action(rs, datas)
-
-            elif button_type == 'object':
-                if not self.id:
-                    return
-                context = self.context_get()
-                if 'context' in attrs:
-                    context.update(self.expr_eval(attrs['context'], check_load=False))
-                result = rpc.session.rpc_exec_auth('/object', 'execute',
-                                                   self.resource,attrs['name'], [id], context)
-                if isinstance(result, dict):
-                    if not result.get('nodestroy', False):
-                        screen.window.destroy()
-                    obj._exec_action(result, {}, context=context)
-
-            elif button_type == 'action':
-                action_id = int(attrs['name'])
-                context = screen.context.copy()
-                if 'context' in attrs:
-                    context.update(self.expr_eval(attrs['context'], check_load=False))
-                datas = {'model':self.resource,
-                         'id': id or False,
-                         'ids': id and [id] or [],
-                         'report_type': 'pdf'
-                         }
-                obj.execute(action_id, datas, context=context)
-            else:
-                raise Exception, 'Unallowed button type'
-            if screen.current_model and screen.current_view.view_type != 'tree':
-                screen.reload()
-
-
+                        reload = False
+                elif button_type == 'action':
+                    action_id = int(attrs['name'])
+                    context = screen.context.copy()
+                    if 'context' in attrs:
+                        context.update(self.expr_eval(attrs['context'], check_load=False))
+                    datas = {'model':self.resource,
+                             'id': id or False,
+                             'ids': id and [id] or [],
+                             'report_type': 'pdf'
+                             }
+                    obj.execute(action_id, datas, context=context)
+                else:
+                    raise Exception, 'Unallowed button type'
+                if reload and screen.current_model and screen.current_view.view_type != 'tree':
+                    screen.reload()
+        finally:
+            if not reset:
+                common.reset_busy_cursor(cursor)
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
 

=== modified file 'bin/widget/view/form.py'
--- bin/widget/view/form.py	2010-10-12 10:40:02 +0000
+++ bin/widget/view/form.py	2010-11-02 09:51:44 +0000
@@ -266,7 +266,9 @@
                                 'ids': [id],
                             }
                         obj = service.LocalService('action.main')
+                        cursor = common.set_busy_cursor()
                         value = obj._exec_action(act, data, context)
+                        common.reset_busy_cursor(cursor)
                         if type in ('print', 'action'):
                             self.screen.reload()
                         return value

_______________________________________________
Mailing list: https://launchpad.net/~openerp-dev-gtk
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~openerp-dev-gtk
More help   : https://help.launchpad.net/ListHelp

Reply via email to