Cédric Krier has proposed merging lp:~pcsol/openobject-client/print_5_0 into 
lp:openobject-client/5.0.

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


  Improve report printing
   
  - Allow to directly print report
  - Allow to send report as attachment

-- 
https://code.launchpad.net/~pcsol/openobject-client/print_5_0/+merge/29061
Your team OpenERP sa GTK client R&D is requested to review the proposed merge 
of lp:~pcsol/openobject-client/print_5_0 into lp:openobject-client/5.0.
=== modified file 'bin/common/common.py'
--- bin/common/common.py	2010-03-23 23:37:45 +0000
+++ bin/common/common.py	2010-07-02 09:58:23 +0000
@@ -3,6 +3,10 @@
 #
 #    OpenERP, Open Source Management Solution
 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+#    Copyright (C) 2007-2010 Cédric Krier.
+#    Copyright (C) 2007-2010 Bertrand Chenal.
+#    Copyright (C) 2008-2010 B2CK SPRL.
+#    Copyright (C) 2010 PCSol.
 #    $Id$
 #
 #    This program is free software: you can redistribute it and/or modify
@@ -26,6 +30,10 @@
 from cgi import escape
 import tools
 import gettext
+import shlex
+import urllib
+import webbrowser
+from string import Template
 
 import os
 import sys
@@ -584,41 +592,178 @@
         obj.create(False, resource, id, [], 'form', None, context,'form,tree')
     return False
 
-def open_file(value, parent):
-    filetype = {}
-    if options['client.filetype']:
-        if isinstance(options['client.filetype'], str):
-            filetype = eval(options['client.filetype'])
+def find_in_path(name):
+    if os.name == "nt":
+        sep = ';'
+    else:
+        sep = ':'
+    path = [directory for directory in os.environ['PATH'].split(sep)
+            if os.path.isdir(directory)]
+    for directory in path:
+        val = os.path.join(directory, name)
+        if os.path.isfile(val) or os.path.islink(val):
+            return val
+    return name
+
+def file_open(filename, type, parent, print_p=False, number=1):
+
+    if print_p:
+        win = gtk.Dialog(_('Print Number'), parent,
+                gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT
+                | gtk.WIN_POS_CENTER_ON_PARENT)
+        win.set_icon(OPENERP_ICON)
+        hbox = gtk.HBox(homogeneous=True)
+        hbox.pack_start(gtk.Label(_('Number')), expand=False, fill=False)
+        adj = gtk.Adjustment(0.0, -sys.maxint, sys.maxint, 1.0, 5.0)
+        widget = gtk.SpinButton(adj, 1, digits=0)
+        widget.set_numeric(True)
+        widget.set_width_chars(5)
+        widget.set_activates_default(True)
+        widget.set_value(number)
+        hbox.pack_start(widget, expand=True, fill=False)
+        win.vbox.add(hbox)
+        win.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
+        win.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
+        win.resize(200, 200)
+        win.show_all()
+        res = win.run()
+        number = widget.get_value_as_int()
+        if parent:
+            parent.present()
+        win.destroy()
+        if res != gtk.RESPONSE_OK:
+            return False
+    else:
+        number = 1
+
+    if os.name == 'nt':
+        operation = 'open'
+        if print_p:
+            operation = 'print'
+        try:
+            for i in xrange(number):
+                os.startfile(os.path.normpath(filename), operation)
+        except:
+            # Try without operation, it is not supported on version < 2.5
+            try:
+                os.startfile(os.path.normpath(filename))
+            except:
+                save_name = file_selection(_('Save As...'), parent=parent,
+                        action=gtk.FILE_CHOOSER_ACTION_SAVE)
+                if save_name:
+                    file_p = open(filename, 'rb')
+                    save_p = open(save_name, 'wb+')
+                    save_p.write(file_p.read())
+                    save_p.close()
+                    file_p.close()
+        return
+    elif os.name == 'mac' or \
+            (hasattr(os, 'uname') and os.uname()[0] == 'Darwin'):
+        pid = os.fork()
+        if not pid:
+            pid = os.fork()
+            if not pid:
+                try:
+                    os.execv('/usr/bin/open', ['/usr/bin/open', filename])
+                except:
+                    sys.exit(0)
+            time.sleep(0.1)
+            sys.exit(0)
+        os.waitpid(pid, 0)
+        return
+    cmd = ''
+    if isinstance(options['extensions.filetype'], basestring):
+        extensions_filetype = eval(options['extensions.filetype'])
+    if type in extensions_filetype:
+        if print_p:
+            cmd = extensions_filetype[type][1]
         else:
-            filetype = options['client.filetype']
-    root, ext = os.path.splitext(value)
-    cmd = False
-    if ext[1:] in filetype:
-        cmd = filetype[ext[1:]] % (value)
-    if not cmd:
-        cmd = file_selection(_('Open with...'),
-                parent=parent)
-        if cmd:
-            cmd = cmd + ' %s'
-            filetype[ext[1:]] = cmd
-            options['client.filetype'] = filetype
-            options.save()
-            cmd = cmd % (value)
-    if cmd:
+            cmd = extensions_filetype[type][0]
+    if not cmd:
+        #TODO add dialog box
+        pass
+    if not cmd:
+        save_name = file_selection(_('Save As...'), parent=parent,
+                action=gtk.FILE_CHOOSER_ACTION_SAVE)
+        if save_name:
+            file_p = open(filename, 'rb')
+            save_p = open(save_name, 'wb+')
+            save_p.write(file_p.read())
+            save_p.close()
+            file_p.close()
+        return
+    cmd = cmd % filename
+    args = shlex.split(str(cmd))
+    prog = find_in_path(args[0])
+    args[0] = os.path.basename(args[0])
+    if print_p:
+        for i in xrange(number):
+            os.spawnv(os.P_WAIT, prog, args)
+        return
+    pid = os.fork()
+    if not pid:
+        pid = os.fork()
+        if not pid:
+            try:
+                os.execv(prog, args)
+            except:
+                sys.exit(0)
+        time.sleep(0.1)
+        sys.exit(0)
+    os.waitpid(pid, 0)
+
+def mailto(to=None, cc=None, subject=None, body=None, attachment=None):
+    if options['client.email']:
+        cmd = Template(options['client.email']).substitute(
+                to=to or '',
+                cc=cc or '',
+                subject=subject or '',
+                body=body or '',
+                attachment=attachment or '',
+                )
+        args = shlex.split(str(cmd))
+        prog = find_in_path(args[0])
+        args[0] = os.path.basename(args[0])
+        if os.name == 'nt':
+            os.spawnv(os.P_NOWAIT, prog, args)
+            return
         pid = os.fork()
         if not pid:
             pid = os.fork()
             if not pid:
-                prog, args = cmd.split(' ', 1)
-                args = [os.path.basename(prog)] + args.split(' ')
                 try:
-                    os.execvp(prog, args)
+                    os.execv(prog, args)
                 except:
-                    pass
+                    sys.exit(0)
             time.sleep(0.1)
             sys.exit(0)
         os.waitpid(pid, 0)
-
+        return
+    #http://www.faqs.org/rfcs/rfc2368.html
+    url = "mailto:"
+    if to:
+        if isinstance(to, unicode):
+            to = to.encode('utf-8')
+        url += urllib.quote(to.strip(), "@,")
+    url += '?'
+    if cc:
+        if isinstance(cc, unicode):
+            cc = cc.encode('utf-8')
+        url += "&cc=" + urllib.quote(cc, "@,")
+    if subject:
+        if isinstance(subject, unicode):
+            subject = subject.encode('utf-8')
+        url += "&subject=" + urllib.quote(subject, "")
+    if body:
+        if isinstance(body, unicode):
+            body = body.encode('utf-8')
+        body = "\r\n".join(body.splitlines())
+        url += "&body=" + urllib.quote(body, "")
+    if attachment:
+        if isinstance(attachment, unicode):
+            attachment = attachment.encode('utf-8')
+        url += "&attachment=" + urllib.quote(attachment, "")
+    webbrowser.open(url, new=1)
 
 # Color set
 

=== modified file 'bin/modules/action/main.py'
--- bin/modules/action/main.py	2010-06-18 13:52:51 +0000
+++ bin/modules/action/main.py	2010-07-02 09:58:23 +0000
@@ -3,6 +3,10 @@
 #
 #    OpenERP, Open Source Management Solution	
 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+#    Copyright (C) 2007-2010 Cédric Krier.
+#    Copyright (C) 2007-2010 Bertrand Chenal.
+#    Copyright (C) 2008-2010 B2CK SPRL.
+#    Copyright (C) 2010 PCSol.
 #    $Id$
 #
 #    This program is free software: you can redistribute it and/or modify
@@ -24,10 +28,10 @@
 import time
 import base64
 import datetime
+import tempfile
 import service
 import rpc
 import wizard
-import printer
 import common
 import tools
 import options
@@ -37,7 +41,10 @@
     def __init__(self, name='action.main'):
         service.Service.__init__(self, name)
 
-    def exec_report(self, name, data, context={}):
+    def exec_report(self, name, data, direct_print=False,
+            email_print=False, email=None, context=None):
+        if context is None:
+            context = {}
         datas = data.copy()
         ids = datas['ids']
         del datas['ids']
@@ -64,7 +71,26 @@
             if attempt>max_attemps:
                 common.message(_('Printing aborted, too long delay !'))
                 return False
-        printer.print_data(val)
+        print_p = direct_print
+        if 'print_p' in val:
+            print_p = True
+        type = val['format']
+        name = val.get('name', name)
+        data = val['result']
+        number = val.get('number', 1)
+        dtemp = tempfile.mkdtemp(prefix='openerp_')
+        fp_name = os.path.join(dtemp,
+                name.replace(os.sep, ' ').replace(os.altsep or os.sep, '_') \
+                        + os.extsep + type)
+        file_d = open(fp_name, 'wb')
+        file_d.write(base64.decodestring(data))
+        file_d.close()
+        if email_print:
+            common.mailto(to=email.get('to'), cc=email.get('cc'),
+                subject=email.get('subject'), body=email.get('body'),
+                attachment=fp_name)
+        else:
+            common.file_open(fp_name, type, None, print_p=print_p, number=number)
         return True
 
     def execute(self, act_id, datas, type=None, context={}):
@@ -154,14 +180,20 @@
                 del datas['window']
             datas.update(action.get('datas',{}))
             datas['report_id'] = action['report_id']
-            self.exec_report('custom', datas, context)
+            self.exec_report('custom', datas,
+                    direct_print=action.get('direct_print', False),
+                    email_print=action.get('email_print', False),
+                    email=action.get('email'), context=context)
 
         elif action['type']=='ir.actions.report.xml':
             if 'window' in datas:
                 win=datas['window']
                 del datas['window']
             datas.update(action.get('datas',{}))
-            self.exec_report(action['report_name'], datas, context)
+            self.exec_report(action['report_name'], datas,
+                    direct_print=action.get('direct_print', False),
+                    email_print=action.get('email_print', False),
+                    email=action.get('email'), context=context)
 
         elif action['type']=='ir.actions.act_url':
             tools.launch_browser(action.get('url',''))

=== modified file 'bin/modules/gui/main.py'
--- bin/modules/gui/main.py	2010-02-26 11:48:01 +0000
+++ bin/modules/gui/main.py	2010-07-02 09:58:23 +0000
@@ -897,7 +897,6 @@
         def fnc_menuitem(menuitem, opt_name):
             options.options[opt_name] = menuitem.get_active()
         dict = {
-            'on_opt_print_preview_activate': (fnc_menuitem, 'printer.preview', 'opt_print_preview'),
             'on_opt_form_toolbar_activate': (fnc_menuitem, 'form.toolbar', 'opt_form_toolbar'),
         }
         self.glade.get_widget('menubar_'+(options.options['client.toolbar'] or 'both')).set_active(True)

=== modified file 'bin/openerp.glade'
--- bin/openerp.glade	2010-03-23 23:43:06 +0000
+++ bin/openerp.glade	2010-07-02 09:58:23 +0000
@@ -1033,32 +1033,6 @@
                           </widget>
                         </child>
                         <child>
-                          <widget class="GtkImageMenuItem" id="printer">
-                            <property name="visible">True</property>
-                            <property name="label" translatable="yes">_Print</property>
-                            <property name="use_underline">True</property>
-                            <child>
-                              <widget class="GtkMenu" id="printer_menu">
-                                <child>
-                                  <widget class="GtkCheckMenuItem" id="opt_print_preview">
-                                    <property name="visible">True</property>
-                                    <property name="label" translatable="yes">Previe_w before print</property>
-                                    <property name="use_underline">True</property>
-                                    <signal name="activate" handler="on_opt_print_preview_activate"/>
-                                  </widget>
-                                </child>
-                              </widget>
-                            </child>
-                            <child internal-child="image">
-                              <widget class="GtkImage" id="image4238">
-                                <property name="visible">True</property>
-                                <property name="stock">gtk-print</property>
-                                <property name="icon_size">1</property>
-                              </widget>
-                            </child>
-                          </widget>
-                        </child>
-                        <child>
                           <widget class="GtkSeparatorMenuItem" id="separator5">
                             <property name="visible">True</property>
                           </widget>
@@ -1868,7 +1842,12 @@
 The whole source code is distributed under
 the terms of the GNU Public Licence.
 
-(c) 2003-TODAY, Tiny sprl
+Copyright (C) 2003-TODAY, Tiny sprl
+Copyright (C) 2007-2010 Cédric Krier.
+Copyright (C) 2007-2010 Bertrand Chenal.
+Copyright (C) 2008-2010 B2CK SPRL.
+Copyright (C) 2010 PCSol.
+
 
 More Info on www.openerp.com !</property>
                       </widget>

=== modified file 'bin/options.py'
--- bin/options.py	2009-12-03 13:00:26 +0000
+++ bin/options.py	2010-07-02 09:58:23 +0000
@@ -3,6 +3,9 @@
 #
 #    OpenERP, Open Source Management Solution	
 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+#    Copyright (C) 2007-2010 Cédric Krier.
+#    Copyright (C) 2008-2010 B2CK SPRL.
+#    Copyright (C) 2010 PCSol
 #    $Id$
 #
 #    This program is free software: you can redistribute it and/or modify
@@ -53,6 +56,22 @@
     else:
         return '.'
 
+def find_path(progs, args):
+    if os.name == 'nt':
+        return ''
+    if os.name == 'mac' or \
+            (hasattr(os, 'uname') and os.uname()[0] == 'Darwin'):
+        return ''
+    paths = [x for x in os.environ['PATH'].split(':')
+            if os.path.isdir(x)]
+    for dir in paths:
+        for prog in progs:
+            val = os.path.join(dir, prog)
+            if os.path.isfile(val) or os.path.islink(val):
+                return val + ' ' + args
+    return ''
+
+
 class configmanager(object):
     
     def __get_prefix(self):
@@ -86,10 +105,6 @@
             'tip.position': 0,
             'survey.position': 0,
             'form.autosave': False,
-            'printer.preview': True,
-            'printer.softpath': 'none',
-            'printer.softpath_html': 'none',
-            'printer.path': 'none',
             'logging.level': 'INFO',
             'logging.output': 'stdout',
             'client.default_path': os.path.expanduser('~'),
@@ -103,6 +118,21 @@
             'help.index': 'http://doc.openerp.com/',
             'help.context': 'http://doc.openerp.com/index.php?model=%(model)s&lang=%(lang)s',
             'client.timeout': 300,
+            'extensions.filetype': repr({
+                'odt':  (find_path(['ooffice', 'ooffice2'], '"%s"'),
+                    find_path(['ooffice', 'ooffice2'], '-p "%s"')),
+                'txt': (find_path(['ooffice', 'ooffice2'], '"%s"'),
+                    find_path(['ooffice', 'ooffice2'], '-p "%s"')),
+                'pdf': (find_path(['evince', 'xpdf', 'gpdf', 'kpdf',
+                    'epdfview', 'acroread'], '"%s"'), ''),
+                'png': (find_path(['feh', 'display', 'qiv', 'eye'], '"%s"'),
+                    ''),
+                'csv': (find_path(['ooffice', 'ooffice2'], '"%s"'),
+                    find_path(['ooffice', 'ooffice2'], '-p "%s"')),
+            }),
+            'client.email': find_path(['thunderbird'], '-compose "to=\'$to\','
+                'cc=\'$cc\',subject=\'$subject\',body=\'$body\','
+                'attachment=\'$attachment\'"'),
         }
         loglevels = ('critical', 'error', 'warning', 'info', 'debug', 'debug_rpc', 'debug_rpc_answer', 'notset')
         parser = optparse.OptionParser(version=_("OpenERP Client %s" % openerp_version))

=== removed directory 'bin/printer'
=== removed file 'bin/printer/__init__.py'
--- bin/printer/__init__.py	2009-01-04 22:13:17 +0000
+++ bin/printer/__init__.py	1970-01-01 00:00:00 +0000
@@ -1,26 +0,0 @@
-# -*- encoding: utf-8 -*-
-##############################################################################
-#
-#    OpenERP, Open Source Management Solution	
-#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
-#    $Id$
-#
-#    This program is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
-#
-#    This program is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-##############################################################################
-
-from printer import *
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-

=== removed file 'bin/printer/printer.py'
--- bin/printer/printer.py	2009-12-07 10:44:05 +0000
+++ bin/printer/printer.py	1970-01-01 00:00:00 +0000
@@ -1,229 +0,0 @@
-# -*- encoding: utf-8 -*-
-##############################################################################
-#
-#    OpenERP, Open Source Management Solution	
-#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
-#    $Id$
-#
-#    This program is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
-#
-#    This program is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-##############################################################################
-
-# ------------------------------------------------------------------- #
-# Module printer
-# ------------------------------------------------------------------- #
-#
-# Supported formats: pdf
-#
-# Print or open a previewer
-#
-
-import os
-import base64
-import options 
-import sys
-import gc
-import common
-import time
-import gtk
-
-class Printer(object):
-
-    def __init__(self):
-        self.openers = {
-            'pdf': self._findPDFOpener,
-            'html': self._findHTMLOpener,
-            'doc': self._findHTMLOpener,
-            'xls': self._findHTMLOpener,
-            'sxw': self._findSXWOpener,
-            'odt': self._findSXWOpener,
-            'tiff': self._findPDFOpener,
-        }
-
-    def _findInPath(self, progs):
-        lstprogs = progs[:]
-        found = {}
-        path = [dir for dir in os.environ['PATH'].split(':')
-                if os.path.isdir(dir)]
-        for dir in path:
-            content = os.listdir(dir)
-            for prog in progs[:]:
-                if prog in content:
-                    return os.path.join(dir, prog)#prog
-                    
-                    progs.remove(prog)
-                    found[prog] = os.path.join(dir, prog)
-        for prog in lstprogs:
-            if prog in found:
-                return found[prog]
-        return ''
-
-    def _findHTMLOpener(self):
-        import webbrowser
-        def opener(fn):
-            webbrowser.open('file://'+fn)
-        return opener
-
-    def __opener(self, fnct):
-        pid = os.fork()
-        if not pid:
-            pid = os.fork()
-            if not pid:
-                fnct()
-            time.sleep(0.1)
-            sys.exit(0)
-        os.waitpid(pid, 0)
-
-    def _findPDFOpener(self):
-        if os.name != 'nt' and os.uname()[0] == 'Darwin' :
-            def opener(fn):
-                self.__opener( lambda: os.system('/usr/bin/open -a Preview ' + fn) )
-            return opener
-        if os.name == 'nt':
-            if options.options['printer.preview']:
-                if options.options['printer.softpath'] is None:
-                    return lambda fn: os.startfile(fn)
-                else:
-                    return lambda fn: os.system(options.options['printer.softpath'] + ' ' + fn)
-            else:
-                return lambda fn: print_w32_filename(fn)
-        else:
-            if options.options['printer.preview']:
-                if options.options['printer.softpath'] is None:
-                    prog = self._findInPath(['xdg-open', 'evince', 'xpdf', 'gpdf', 'kpdf', 'epdfview', 'acroread', 'open'])
-                    def opener(fn):
-                        self.__opener( lambda: os.execv(prog, (os.path.basename(prog), fn) ))
-                    return opener
-                else:
-                    def opener(fn):
-                        self.__opener( lambda: os.execv(options.options['printer.softpath'], (os.path.basename(options.options['printer.softpath']), fn)) )
-                    return opener
-            else:
-                return lambda fn: print_linux_filename(fn)
-    
-    def _findSXWOpener(self):
-        if os.name == 'nt':
-            return lambda fn: os.startfile(fn)
-        else:
-            if options.options['printer.softpath_html'] is None:
-                prog = self._findInPath(['ooffice', 'ooffice2', 'openoffice', 'soffice'])
-                def opener(fn):
-                    pid = os.fork()
-                    if not pid:
-                        pid = os.fork()
-                        if not pid:
-                            os.execv(prog, (os.path.basename(prog),fn))
-                        time.sleep(0.1)
-                        sys.exit(0)
-                    os.waitpid(pid, 0)
-                return opener
-            else:
-                def opener(fn):
-                    pid = os.fork()
-                    if not pid:
-                        pid = os.fork()
-                        if not pid:
-                            os.execv(options.options['printer.softpath_html'], (os.path.basename(options.options['printer.softpath_html']),fn))
-                        time.sleep(0.1)
-                        sys.exit(0)
-                    os.waitpid(pid, 0)
-                return opener
-    def print_file(self, fname, ftype, preview=False):
-        app_to_run = None
-        try:
-            filetypes = eval( options.options['extensions.filetype'] )
-            (app, app_print) = filetypes[ftype]
-            if options.options['printer.preview'] or preview:
-                app_to_run = app
-            else:
-                app_to_run = app_print
-        except:
-            pass
-
-        if app_to_run:
-            def open_file(cmd, filename):
-                cmd = cmd.split()
-                found = False
-                for i, v in enumerate(cmd):
-                    if v == '%s':
-                        cmd[i] = filename
-                        found = True
-                        break
-                if not found:
-                    cmd.append(filename)
-
-                import subprocess
-                subprocess.Popen(cmd)
-            open_file(app_to_run, fname)
-
-        else:
-            try:
-                finderfunc = self.openers.get(ftype,False)
-                if not finderfunc:
-                    if sys.platform in ['win32', 'nt']:
-                        os.startfile(fname)
-                    else:
-                        finderfunc = self.openers['html']
-                        opener = finderfunc()
-                        opener(fname)
-                else:
-                    opener = finderfunc()
-                    opener(fname)
-                    gc.collect()
-            except Exception,e:
-                raise Exception(_('Unable to handle %s filetype') % ftype)
-
-printer = Printer()
-
-def print_linux_filename(filename):
-    common.message(_('Linux Automatic Printing not implemented.\nUse preview option !'))
-
-def print_w32_filename(filename):
-    import win32api
-    win32api.ShellExecute (0, "print", filename, None, ".", 0)
-
-def print_data(data):
-    if 'result' not in data:
-        common.message(_('Error no report'))
-        return 
-    if data.get('code','normal')=='zlib':
-        import zlib
-        content = zlib.decompress(base64.decodestring(data['result']))
-    else:
-        content = base64.decodestring(data['result'])
-
-    if data['format'] in printer.openers.keys():
-        import tempfile
-        if data['format']=='html' and os.name=='nt':
-            data['format']='doc'
-        (fileno, fp_name) = tempfile.mkstemp('.'+data['format'], 'openerp_')
-        fp = file(fp_name, 'wb+')
-        fp.write(content)
-        fp.close()
-        os.close(fileno)
-        printer.print_file(fp_name, data['format'])
-    else:
-        fname = common.file_selection(_('Save As...'), filename='report.' + data['format'],
-                action=gtk.FILE_CHOOSER_ACTION_SAVE)
-        if fname:
-            try:
-                fp = file(fname,'wb+')
-                fp.write(content)
-                fp.close()
-            except:
-                common.message(_('Error writing the file!'))
-
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-

=== modified file 'bin/widget/view/form.py'
--- bin/widget/view/form.py	2010-01-05 12:27:50 +0000
+++ bin/widget/view/form.py	2010-07-02 09:58:23 +0000
@@ -3,6 +3,10 @@
 #
 #    OpenERP, Open Source Management Solution	
 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+#    Copyright (C) 2008-2010 Bertrand Chenal.
+#    Copyright (C) 2008-2010 Cedric Krier.
+#    Copyright (C) 2008-2010 B2CK.
+#    Copyright (C) 2010  PCSol.
 #    $Id$
 #
 #    This program is free software: you can redistribute it and/or modify
@@ -91,224 +95,169 @@
         self.widgets = dict([(name, ViewWidget(self, widget, name)) for name, widget in children.items()])
 
         if toolbar:
-            hb = gtk.HBox()
+            hb = gtk.VBox()
             hb.pack_start(self.widget)
-#            self.hpaned = gtk.HPaned()
-#            self.hpaned.pack1(self.widget,True,False)
-
-            #tb = gtk.Toolbar()
-            #tb.set_orientation(gtk.ORIENTATION_VERTICAL)
-            #tb.set_style(gtk.TOOLBAR_BOTH_HORIZ)
-            #tb.set_icon_size(gtk.ICON_SIZE_MENU)
-            tb = gtk.VBox()
-
-            eb = gtk.EventBox()
-            eb.add(tb)
-            eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("lightgrey"))
-
-
-            hb.pack_start(eb, False, False)
+
+            gtktoolbar = gtk.Toolbar()
+            gtktoolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL)
+            gtktoolbar.set_style(gtk.TOOLBAR_BOTH)
+            gtktoolbar.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("lightgrey"))
+
+            hb.pack_start(gtktoolbar, False, False)
             self.widget = hb
-#            self.hpaned.pack2(eb,False,True)
-#            self.hpaned.connect("button-press-event",self.move_paned_press)
-#            self.hpaned.connect("button-release-event",self.move_paned_release,window)
-#            window.connect("window-state-event",self.move_paned_window,window)
-#            self.widget = self.hpaned
-
-
-            sep = False
-            #setLabel={'print':'Reports','action':'Wizards','relate':'Direct Links'}
-            
+
             for icontype in ('print', 'action', 'relate'):
-                    
-                if icontype in ('action','relate') and sep:
-                    #tb.insert(gtk.SeparatorToolItem(), -1)
-                    tb.pack_start(gtk.HSeparator(), False, False, 2)
-                    sep = False
-                     
-                #list_done = []     
                 for tool in toolbar[icontype]:
-                    #if icontype not in list_done:
-                    #    l = gtk.Label('<b>' + setLabel[icontype] + '</b>')
-                    #    l.set_use_markup(True)
-#                   #     l.set_alignment(0.0, 0.5) # If Labels want to be Left-aligned
-                    #    tb.pack_start(l, False, False, 3)
-                    #    tb.pack_start(gtk.HSeparator(), False, False, 2)
-                    #    list_done.append(icontype)
                     iconstock = {
                         'print': gtk.STOCK_PRINT,
                         'action': gtk.STOCK_EXECUTE,
                         'relate': gtk.STOCK_JUMP_TO,
                     }.get(icontype, gtk.STOCK_ABOUT)
 
-                    icon = gtk.Image()
-                    icon.set_from_stock(iconstock, gtk.ICON_SIZE_BUTTON)
-                    lbl = gtk.Label(tool['string'])
-                    lbl.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("black"))
-                    hb = gtk.HBox(False, 5)
-                    hb.pack_start(icon, False, False)
-                    hb.pack_start(lbl, False, False)
-
-                    tbutton = gtk.Button()
-                    tbutton.add(hb)
-                    tbutton.set_relief(gtk.RELIEF_NONE)
-                    tb.pack_start(tbutton, False, False, 2)
-
-                    #tbutton = gtk.ToolButton()
-                    #tbutton.set_label_widget(hb) #tool['string'])
-                    #tbutton.set_stock_id(iconstock)
-                    #tb.insert(tbutton,-1)
-
-                    def _action(button, action, type):
-                        data={}
-                        context=self.screen.context
-                        act=action.copy()
-                        if type in ('print', 'action'):
-                            self.screen.save_current()
-                            id = self.screen.current_model and self.screen.current_model.id
-                            if not (id):
-                                common.message(_('You must save this record to use the relate button !'))
-                                return False
-                            self.screen.display()
-                            data = {
-                                'model': self.screen.name,
-                                'id': id,
-                                'ids': [id],
-                                'report_type': act.get('report_type', 'pdf'),
-                            }
-                        if type == 'relate':
-                            id = self.screen.current_model and self.screen.current_model.id
-                            if not (id):
-                                common.message(_('You must select a record to use the relate button !'))
-                                return False
-                            act['domain'] = self.screen.current_model.expr_eval(act['domain'], check_load=False)
-                            act['context'] = str(self.screen.current_model.expr_eval(act['context'], check_load=False))
-                        obj = service.LocalService('action.main')
-                        value = obj._exec_action(act, data, context)
-                        if type in ('print', 'action'):
-                            self.screen.reload()
-                        return value
-
-                    def _translate_label(self, event, tool, window):
-                        if event.button != 3:
-                            return False
-                        def callback(self, tool, window):
-                            lang_ids = rpc.session.rpc_exec_auth('/object',
-                                    'execute', 'res.lang', 'search',
-                                    [('translatable', '=', '1')])
-                            if not lang_ids:
-                                common.message(_('No other language available!'),
-                                        parent=window)
-                                return False
-                            langs = rpc.session.rpc_exec_auth('/object',
-                                    'execute', 'res.lang', 'read', lang_ids,
-                                    ['code', 'name'])
-
-                            win = gtk.Dialog(_('Add Translation'), window,
-                                    gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
-                            win.vbox.set_spacing(5)
-                            win.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
-                            win.set_icon(common.OPENERP_ICON)
-                            vbox = gtk.VBox(spacing=5)
-
-                            entries_list = []
-                            for lang in langs:
-                                code = lang['code']
-                                val = rpc.session.rpc_exec_auth('/object',
-                                        'execute', tool['type'], 'read',
-                                        [tool['id']], ['name'], {'lang': code})
-                                val = val[0]
-
-                                label = gtk.Label(lang['name'])
-                                entry = gtk.Entry()
-                                entry.set_text(val['name'])
-                                entries_list.append((code, entry))
-                                hbox = gtk.HBox(homogeneous=True)
-                                hbox.pack_start(label, expand=False, fill=False)
-                                hbox.pack_start(entry, expand=True, fill=True)
-                                vbox.pack_start(hbox, expand=False, fill=True)
-
-                            vp = gtk.Viewport()
-                            vp.set_shadow_type(gtk.SHADOW_NONE)
-                            vp.add(vbox)
-                            sv = gtk.ScrolledWindow()
-                            sv.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
-                            sv.set_shadow_type(gtk.SHADOW_NONE)
-                            sv.add(vp)
-                            win.vbox.add(sv)
-                            win.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
-                            win.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
-                            win.resize(400,200)
-                            win.show_all()
-                            res = win.run()
-                            if res == gtk.RESPONSE_OK:
-                                to_save = map(lambda x: (x[0],
-                                    x[1].get_text()), entries_list)
-                                while to_save:
-                                    code, val = to_save.pop()
-                                    rpc.session.rpc_exec_auth('/object',
-                                            'execute', tool['type'],
-                                            'write', [tool['id']],
-                                            {'name': val}, {'lang': code})
-                            window.present()
-                            win.destroy()
-                            return res
-
+                    if hasattr(gtk, 'MenuToolButton'):
+                        tbutton = gtk.MenuToolButton(iconstock)
+                    else:
+                        tbutton = gtk.ToolButton(iconstock)
+                    tbutton.set_use_underline(True)
+
+                    text = tool['string']
+                    if '_' not in text:
+                        text = '_' + text
+                    tbutton.set_label(text)
+                    gtktoolbar.insert(tbutton, -1)
+
+                    tbutton.connect('clicked', self._sig_clicked, tool,
+                            icontype)
+
+                    if hasattr(gtk, 'MenuToolButton'):
                         menu = gtk.Menu()
-                        item = gtk.ImageMenuItem(_('Translate label'))
-                        item.connect("activate", callback, tool, window)
-                        item.set_sensitive(1)
-                        item.show()
-                        menu.append(item)
-                        menu.popup(None,None,None,event.button,event.time)
-                        return True
-
-                    tbutton.connect('clicked', _action, tool, icontype)
-
-                    tbutton.connect('button_press_event', _translate_label,
-                            tool, self.window)
-
-                    sep = True
-                    
-#    def move_paned_press(self, widget, event):
-#        if not self.prev:
-#            self.prev = self.hpaned.get_position()
-#            return False
-#        if self.prev and not self.flag:
-#            self.prev = self.hpaned.get_position()
-#            return False
-#
-#    def move_paned_release(self, widget, event, w):
-#        if self.hpaned.get_position()<self.current and self.hpaned.get_position()!=self.prev:
-#            self.prev = self.hpaned.get_position()
-#        else:
-#            self.current= self.hpaned.get_position()
-#        if not self.flag and self.current == self.prev:
-#            self.flag=True
-#            self.hpaned.set_position(w.get_size()[0])
-#        elif not self.flag and self.current>self.prev:
-#            if self.hpaned.get_position()<self.current:
-#                self.hpaned.set_position(self.prev)
-#            else:
-#                self.hpaned.set_position(self.current)
-#        elif self.flag:
-#            if self.current<self.prev:
-#                self.hpaned.set_position(self.current)
-#            elif self.current>self.prev:
-#                self.hpaned.set_position(self.prev)
-#            self.flag=False
-#        self.current = self.hpaned.get_position() - 7
-#        return False
-#
-#    def move_paned_window(self, widget, event, w):
-#        if not self.prev:
-#            self.prev=self.hpaned.get_position()
-#        self.hpaned.set_position(self.prev)
-#        self.prev = 0
-#        self.current = 0
-#        self.flag = False
-#        return False                    
-
+                        if icontype == 'print':
+                            for mtype, text in (('print', _('_Direct Print')),
+                                    ('email', _('_Email as Attachment'))):
+                                menuitem = gtk.MenuItem(text)
+                                tool = tool.copy()
+                                if mtype == 'print':
+                                    tool['direct_print'] = True
+                                    tool['email_print'] = False
+                                else:
+                                    tool['direct_print'] = False
+                                    tool['email_print'] = True
+                                menuitem.connect('activate', self._sig_clicked,
+                                        tool, icontype)
+                                menu.add(menuitem)
+                                menuitem.show()
+                        menuitem = gtk.MenuItem(_('Translate Label'))
+                        menuitem.connect('activate', self._translate_label, tool)
+                        menu.add(menuitem)
+                        menuitem.show()
+                        tbutton.set_menu(menu)
+
+    def _sig_clicked(self, widget, action, atype):
+        return self._action(action, atype)
+
+    def _action(self, action, atype):
+        data={}
+        context=self.screen.context
+        act=action.copy()
+        if atype in ('print', 'action'):
+            self.screen.save_current()
+            obj_id = self.screen.current_model and self.screen.current_model.id
+            if not (obj_id):
+                if atype in ('print'):
+                    common.message(_('You must save this record '
+                        'to be able to use the print button!'))
+                if atype in ('action'):
+                    common.message(_('You must save this record '
+                        'to be able to use the action button!'))
+                return False
+            email = {}
+            if 'email' in action:
+                email = self.screen.current_model.expr_eval(action['email'])
+                if not email:
+                    email = {}
+            email['subject'] = action['name'].replace('_', '')
+            act['email'] = email
+            self.screen.display()
+        if atype == 'relate':
+            obj_id = self.screen.current_model and self.screen.current_model.id
+            if not obj_id:
+                common.message(_('You must select a record to use the relate button !'))
+                return False
+            act['domain'] = self.screen.current_model.expr_eval(act['domain'], check_load=False)
+            act['context'] = str(self.screen.current_model.expr_eval(act['context'], check_load=False))
+
+        data = {
+            'model': self.screen.name,
+            'id': obj_id,
+            'ids': [obj_id],
+        }
+
+        obj = service.LocalService('action.main')
+        value = obj._exec_action(act, data, context)
+        self.screen.reload()
+        return value
+
+    def _translate_label(self, widget, tool):
+        lang_ids = rpc.session.rpc_exec_auth('/object',
+                'execute', 'res.lang', 'search',
+                [('translatable', '=', '1')])
+        if not lang_ids:
+            common.message(_('No other language available!'),
+                    parent=self.window)
+            return False
+        langs = rpc.session.rpc_exec_auth('/object',
+                'execute', 'res.lang', 'read', lang_ids,
+                ['code', 'name'])
+
+        win = gtk.Dialog(_('Add Translation'), self.window,
+                gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
+        win.vbox.set_spacing(5)
+        win.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
+        win.set_icon(common.OPENERP_ICON)
+        vbox = gtk.VBox(spacing=5)
+
+        entries_list = []
+        for lang in langs:
+            code = lang['code']
+            val = rpc.session.rpc_exec_auth('/object',
+                    'execute', tool['type'], 'read',
+                    [tool['id']], ['name'], {'lang': code})
+            val = val[0]
+
+            label = gtk.Label(lang['name'])
+            entry = gtk.Entry()
+            entry.set_text(val['name'])
+            entries_list.append((code, entry))
+            hbox = gtk.HBox(homogeneous=True)
+            hbox.pack_start(label, expand=False, fill=False)
+            hbox.pack_start(entry, expand=True, fill=True)
+            vbox.pack_start(hbox, expand=False, fill=True)
+
+        vp = gtk.Viewport()
+        vp.set_shadow_type(gtk.SHADOW_NONE)
+        vp.add(vbox)
+        sv = gtk.ScrolledWindow()
+        sv.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+        sv.set_shadow_type(gtk.SHADOW_NONE)
+        sv.add(vp)
+        win.vbox.add(sv)
+        win.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
+        win.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
+        win.resize(400,200)
+        win.show_all()
+        res = win.run()
+        if res == gtk.RESPONSE_OK:
+            to_save = map(lambda x: (x[0],
+                x[1].get_text()), entries_list)
+            while to_save:
+                code, val = to_save.pop()
+                rpc.session.rpc_exec_auth('/object',
+                        'execute', tool['type'],
+                        'write', [tool['id']],
+                        {'name': val}, {'lang': code})
+        self.window.present()
+        win.destroy()
+        return res
 
     def __getitem__(self, name):
         return self.widgets[name]

=== modified file 'bin/widget/view/form_gtk/binary.py'
--- bin/widget/view/form_gtk/binary.py	2009-02-03 21:58:37 +0000
+++ bin/widget/view/form_gtk/binary.py	2010-07-02 09:58:23 +0000
@@ -34,7 +34,6 @@
 import interface
 import common
 import options
-import printer
 
 
 class wid_binary(interface.widget_interface):
@@ -119,7 +118,7 @@
                 os.write(fileno, base64.decodestring(data))
                 os.close(fileno)
 
-                printer.printer.print_file(fp_name, ext, preview=True)
+                common.file_open(fp_name, ext, self.parent)
         except Exception, ex:
             common.message(_('Error reading the file: %s') % str(ex))
             raise

=== modified file 'bin/widget/view/form_gtk/url.py'
--- bin/widget/view/form_gtk/url.py	2009-01-04 22:13:17 +0000
+++ bin/widget/view/form_gtk/url.py	2010-07-02 09:58:23 +0000
@@ -22,6 +22,7 @@
 
 import gettext
 import gtk
+import os.path
 
 import common
 import interface
@@ -120,7 +121,8 @@
 
     def button_clicked(self, widget):
         value = self.entry.get_text()
-        common.open_file(value, self._window)
+        _, type = os.path.splitext(value)
+        common.file_open(value, type, self._window)
 
 
 

=== modified file 'bin/widget/view/list.py'
--- bin/widget/view/list.py	2009-04-27 07:12:26 +0000
+++ bin/widget/view/list.py	2010-07-02 09:58:23 +0000
@@ -3,7 +3,10 @@
 #
 #    OpenERP, Open Source Management Solution	
 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
-#    Copyright (c) 2008-2009 B2CK, Bertrand Chenal, Cedric Krier (D&D in lists)
+#    Copyright (C) 2008-2010 Bertrand Chenal.
+#    Copyright (C) 2008-2010 Cedric Krier.
+#    Copyright (C) 2008-2010 B2CK.
+#    Copyright (C) 2010  PCSol.
 #    $Id$
 #
 #    This program is free software: you can redistribute it and/or modify
@@ -29,6 +32,7 @@
 import service
 import locale
 from interface import parser_view
+import options
 
 
 class AdaptModelGroup(gtk.GenericTreeModel):
@@ -172,6 +176,59 @@
                 hbox.pack_start(hbox2, expand=False, fill=False, padding=12)
             hbox.show_all()
 
+        if toolbar and (toolbar['print'] or toolbar['action']):
+            hbox = gtk.HBox()
+            self.widget.pack_start(hbox, expand=False, fill=False)
+
+            gtktoolbar = gtk.Toolbar()
+            gtktoolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL)
+            gtktoolbar.set_style(gtk.TOOLBAR_BOTH)
+            gtktoolbar.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("lightgrey"))
+            hbox.pack_start(gtktoolbar, True, True)
+
+            for icontype in ('print', 'action'):
+                if not toolbar[icontype]:
+                    continue
+
+                for tool in toolbar[icontype]:
+                    iconstock = {
+                        'print': gtk.STOCK_PRINT,
+                        'action': gtk.STOCK_EXECUTE,
+                    }.get(icontype)
+
+                    if hasattr(gtk, 'MenuToolButton') and icontype == 'print':
+                        tbutton = gtk.MenuToolButton(iconstock)
+                    else:
+                        tbutton = gtk.ToolButton(iconstock)
+                    tbutton.set_use_underline(True)
+                    text = tool['string']
+                    if '_' not in text:
+                        text = '_' + text
+                    tbutton.set_label(text)
+                    gtktoolbar.insert(tbutton, -1)
+
+                    tbutton.connect('clicked', self._sig_clicked, tool, icontype)
+
+                    if hasattr(gtk, 'MenuToolButton') and icontype == 'print':
+                        menu = gtk.Menu()
+                        for mtype, text in (('print', _('_Direct Print')),
+                                ('email', _('Email as Attachment'))):
+                            menuitem = gtk.MenuItem(text)
+                            tool2 = tool.copy()
+                            if mtype == 'print':
+                                tool2['direct_print'] = True
+                                tool2['email_print'] = False
+                            else:
+                                tool2['direct_print'] = False
+                                tool2['email_print'] = True
+                            menuitem.connect('activate', self._sig_clicked, tool2,
+                                    icontype)
+                            menu.add(menuitem)
+                            menuitem.show()
+                        tbutton.set_menu(menu)
+
+            hbox.show_all()
+
         self.display()
 
         self.widget_tree.connect('button-press-event', self.__hello)
@@ -196,6 +253,34 @@
             self.widget_tree.connect('drag-data-received', self.drag_data_received)
             self.widget_tree.connect('drag-data-delete', self.drag_data_delete)
 
+    def _sig_clicked(self, widget, action, atype):
+        return self._action(action, atype)
+
+    def _action(self, action, atype):
+        context = self.screen.context.copy()
+        act = action.copy()
+        obj_ids = self.screen.current_view.sel_ids_get()
+        obj_id = self.screen.current_model.id
+        if not obj_ids and not obj_id:
+            common.message(_('No record selected!'), self.window)
+            return False
+        email = {}
+        if action.get('email'):
+            email = self.screen.current_model.expr_eval(action['email'])
+            if not email:
+                email = {}
+        email['subject'] = action['name'].replace('_', '')
+        act['email'] = email
+        data = {
+            'model': self.screen.name,
+            'id': obj_id,
+            'ids': obj_ids,
+        }
+        obj = service.LocalService('action.main')
+        value = obj._exec_action(act, data, context)
+        self.screen.reload()
+        return value
+
     def drag_drop(self, treeview, context, x, y, time):
         treeview.emit_stop_by_name('drag-drop')
         treeview.drag_get_data(context, context.targets[-1], time)

_______________________________________________
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