diff --git a/debian/control b/debian/control index a4c1b050c0a..74cd027427a 100644 --- a/debian/control +++ b/debian/control @@ -47,7 +47,13 @@ Depends: Conflicts: tinyerp-server, openerp-server, openerp-web Replaces: tinyerp-server, openerp-server, openerp-web Recommends: - graphviz, ghostscript, postgresql, python-matplotlib, poppler-utils + antiword, + graphviz, + ghostscript, + postgresql, + python-gevent, + python-matplotlib, + poppler-utils Description: OpenERP Enterprise Resource Management OpenERP, previously known as TinyERP, is a complete ERP and CRM. The main features are accounting (analytic and financial), stock management, sales and diff --git a/openerp/addons/base/res/__init__.py b/openerp/addons/base/res/__init__.py index 50807e20116..24bded0cc7f 100644 --- a/openerp/addons/base/res/__init__.py +++ b/openerp/addons/base/res/__init__.py @@ -25,6 +25,7 @@ import res_partner import res_bank import res_config import res_currency +import res_font import res_company import res_users import res_request diff --git a/openerp/addons/base/res/res_company.py b/openerp/addons/base/res/res_company.py index d61963dbce4..6e74dbf1547 100644 --- a/openerp/addons/base/res/res_company.py +++ b/openerp/addons/base/res/res_company.py @@ -112,9 +112,6 @@ class res_company(osv.osv): def _get_companies_from_partner(self, cr, uid, ids, context=None): return self.pool['res.company'].search(cr, uid, [('partner_id', 'in', ids)], context=context) - - def _get_font(self, cr, uid, context=None): - return sorted(customfonts.RegisterCustomFonts()) _columns = { 'name': fields.related('partner_id', 'name', string='Company Name', size=128, required=True, store=True, type='char'), @@ -128,7 +125,7 @@ class res_company(osv.osv): 'rml_footer': fields.text('Report Footer', help="Footer text displayed at the bottom of all reports."), 'rml_footer_readonly': fields.related('rml_footer', type='text', string='Report Footer', readonly=True), 'custom_footer': fields.boolean('Custom Footer', help="Check this to define the report footer manually. Otherwise it will be filled in automatically."), - 'font': fields.selection(_get_font, "Font",help="Set the font into the report header, will be used for every RML report of the company"), + 'font': fields.many2one('res.font', string="Font",help="Set the font into the report header, it will be used as default font in the RML reports of the user company"), 'logo': fields.related('partner_id', 'image', string="Logo", type="binary"), 'logo_web': fields.function(_get_logo_web, string="Logo Web", type="binary", store={ 'res.company': (lambda s, c, u, i, x: i, ['partner_id'], 10), @@ -192,10 +189,11 @@ class res_company(osv.osv): default_para = re.sub('fontName.?=.?".*"', 'fontName="%s"'% font,header) return re.sub('("%s"\g<3>'% font,default_para) + fontname = self.pool.get('res.font').browse(cr, uid, font, context=context).name return {'value':{ - 'rml_header': _change_header(rml_header,font), - 'rml_header2':_change_header(rml_header2,font), - 'rml_header3':_change_header(rml_header3,font) + 'rml_header': _change_header(rml_header,fontname), + 'rml_header2':_change_header(rml_header2,fontname), + 'rml_header3':_change_header(rml_header3,fontname) }} def on_change_country(self, cr, uid, ids, country_id, context=None): @@ -294,6 +292,15 @@ class res_company(osv.osv): def _get_logo(self, cr, uid, ids): return open(os.path.join( tools.config['root_path'], 'addons', 'base', 'res', 'res_company_logo.png'), 'rb') .read().encode('base64') + def _get_font(self, cr, uid, ids): + font_obj = self.pool.get('res.font') + res = font_obj.search(cr, uid, [('name', '=', 'Helvetica')], limit=1) + if res: + return res[0] + + font_obj.init_no_scan(cr, uid) + return font_obj.search(cr, uid, [('name', '=', 'Helvetica')], limit=1)[0] + _header = """
@@ -388,6 +395,9 @@ class res_company(osv.osv): return {'value': {'rml_header': self._header_letter}} return {'value': {'rml_header': self._header_a4}} + def act_discover_fonts(self, cr, uid, ids, context=None): + return self.pool.get("res.font").discover_fonts(cr, uid, ids, context) + _defaults = { 'currency_id': _get_euro, 'paper_format': 'a4', @@ -395,12 +405,11 @@ class res_company(osv.osv): 'rml_header2': _header2, 'rml_header3': _header3, 'logo':_get_logo, - 'font':'Helvetica', + 'font':_get_font, } _constraints = [ (osv.osv._check_recursion, 'Error! You can not create recursive companies.', ['parent_id']) ] - # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/res/res_company_view.xml b/openerp/addons/base/res/res_company_view.xml index e9acf7940b3..d0f35223bba 100644 --- a/openerp/addons/base/res/res_company_view.xml +++ b/openerp/addons/base/res/res_company_view.xml @@ -80,7 +80,15 @@ - + + + diff --git a/openerp/addons/base/res/res_font.py b/openerp/addons/base/res/res_font.py new file mode 100644 index 00000000000..4218b0b7955 --- /dev/null +++ b/openerp/addons/base/res/res_font.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2009 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from reportlab.pdfbase import ttfonts +from openerp.osv import fields, osv +from openerp.report.render.rml2pdf import customfonts + +import logging + +"""This module allows the mapping of some system-available TTF fonts to +the reportlab engine. + +This file could be customized per distro (although most Linux/Unix ones) +should have the same filenames, only need the code below). + +Due to an awful configuration that ships with reportlab at many Linux +and Ubuntu distros, we have to override the search path, too. +""" +_logger = logging.getLogger(__name__) + + +class res_font(osv.Model): + _name = "res.font" + _description = 'Fonts available' + _order = 'name' + + _columns = { + 'name': fields.char("Name", required=True), + } + + _sql_constraints = [ + ('name_font_uniq', 'unique(name)', 'You can not register two fonts with the same name'), + ] + + def discover_fonts(self, cr, uid, ids, context=None): + """Scan fonts on the file system, add them to the list of known fonts + and create font object for the new ones""" + customfonts.CustomTTFonts = customfonts.BaseCustomTTFonts + + found_fonts = {} + for font_path in customfonts.list_all_sysfonts(): + try: + font = ttfonts.TTFontFile(font_path) + _logger.debug("Found font %s at %s", font.name, font_path) + if not found_fonts.get(font.familyName): + found_fonts[font.familyName] = {'name': font.familyName} + + mode = font.styleName.lower().replace(" ", "") + + customfonts.CustomTTFonts.append((font.familyName, font.name, font_path, mode)) + except ttfonts.TTFError: + _logger.warning("Could not register Font %s", font_path) + + # add default PDF fonts + for family in customfonts.BasePDFFonts: + if not found_fonts.get(family): + found_fonts[family] = {'name': family} + + # remove deleted fonts + existing_font_ids = self.search(cr, uid, [], context=context) + existing_font_names = [] + for font in self.browse(cr, uid, existing_font_ids): + existing_font_names.append(font.name) + if font.name not in found_fonts.keys(): + self.unlink(cr, uid, font.id, context=context) + + # add unknown fonts + for family, vals in found_fonts.items(): + if family not in existing_font_names: + self.create(cr, uid, vals, context=context) + return True + + def init_no_scan(self, cr, uid, context=None): + """Add demo data for PDF fonts without scan (faster for db creation)""" + for font in customfonts.BasePDFFonts: + if not self.search(cr, uid, [('name', '=', font)], context=context): + self.create(cr, uid, {'name':font}, context=context) + return True \ No newline at end of file diff --git a/openerp/report/render/rml2pdf/customfonts.py b/openerp/report/render/rml2pdf/customfonts.py index ede2d91aaed..7f89f324bf7 100644 --- a/openerp/report/render/rml2pdf/customfonts.py +++ b/openerp/report/render/rml2pdf/customfonts.py @@ -37,18 +37,30 @@ should have the same filenames, only need the code below). Due to an awful configuration that ships with reportlab at many Linux and Ubuntu distros, we have to override the search path, too. """ -_fonts_cache = {'registered_fonts': [], 'total_system_fonts': 0} _logger = logging.getLogger(__name__) -# Basic fonts familly included in PDF standart, will always be in the font list +# Basic fonts family included in PDF standart, will always be in the font list BasePDFFonts = [ - ('Helvetica', 'Helvetica'), - ('Times', 'Times'), - ('Courier', 'Courier'), + 'Helvetica', + 'Times', + 'Courier' ] # List of fonts found on the disk -CustomTTFonts = [] +CustomTTFonts = BaseCustomTTFonts = [ ('Helvetica', "DejaVu Sans", "DejaVuSans.ttf", 'normal'), + ('Helvetica', "DejaVu Sans Bold", "DejaVuSans-Bold.ttf", 'bold'), + ('Helvetica', "DejaVu Sans Oblique", "DejaVuSans-Oblique.ttf", 'italic'), + ('Helvetica', "DejaVu Sans BoldOblique", "DejaVuSans-BoldOblique.ttf", 'bolditalic'), + ('Times', "Liberation Serif", "LiberationSerif-Regular.ttf", 'normal'), + ('Times', "Liberation Serif Bold", "LiberationSerif-Bold.ttf", 'bold'), + ('Times', "Liberation Serif Italic", "LiberationSerif-Italic.ttf", 'italic'), + ('Times', "Liberation Serif BoldItalic", "LiberationSerif-BoldItalic.ttf", 'bolditalic'), + ('Courier', "FreeMono", "FreeMono.ttf", 'normal'), + ('Courier', "FreeMono Bold", "FreeMonoBold.ttf", 'bold'), + ('Courier', "FreeMono Oblique", "FreeMonoOblique.ttf", 'italic'), + ('Courier', "FreeMono BoldOblique", "FreeMonoBoldOblique.ttf", 'bolditalic'), +] + # Search path for TTF files, in addition of rl_config.TTFSearchPath TTFSearchPath = [ @@ -73,7 +85,7 @@ TTFSearchPath = [ 'c:/windows/fonts' ] -def all_sysfonts_list(): +def list_all_sysfonts(): """ This function returns list of font directories of system. """ @@ -89,76 +101,6 @@ def all_sysfonts_list(): filepath.append(os.path.join(dirname, filename)) return filepath -def init_new_font(familyName, name, font_dir): - return { - 'regular':(familyName, name, font_dir, 'regular'), - 'italic':(), - 'bold':(familyName, name, font_dir, 'bold'), - 'bolditalic':(), - } - -def RegisterCustomFonts(): - """ - This function prepares a list for all system fonts to be registered - in reportlab and returns the updated list with new fonts. - """ - global CustomTTFonts - all_system_fonts = all_sysfonts_list() - if len(all_system_fonts) != _fonts_cache['total_system_fonts']: - font_modes, last_family, registered_font_list, _fonts_cache['registered_fonts'] = {}, "", [], list(BasePDFFonts) - - #Prepares a list of registered fonts. Remove such fonts those don't have cmap for Unicode. - for dirname in all_system_fonts: - try: - font_info = ttfonts.TTFontFile(dirname) - if font_info.styleName in ('Regular','Normal','Book','Medium', 'Roman'): - _fonts_cache['registered_fonts'].append((font_info.name, font_info.fullName)) - registered_font_list.append((font_info.familyName, font_info.name, dirname, font_info.styleName.lower().replace(" ", ""))) - _logger.debug("Found font %s at %s", font_info.name, dirname) - except: - _logger.warning("Could not register Font %s", dirname) - - #Prepare font list for mapping.Each font family requires four type of modes(regular,bold,italic,bolditalic). - #If all modes are not found, dummy entries are made for remaining modes. - for familyName, name, font_dir, mode in sorted(registered_font_list): - if not last_family or not font_modes: - last_family = familyName - font_modes = init_new_font(familyName, name, font_dir) - - if last_family != familyName: - # new font familly, adding previous to the list of fonts - if not font_modes['italic']: - font_modes['italic'] = font_modes['regular'][:3]+('italic',) - if not font_modes['bolditalic']: - font_modes['bolditalic'] = font_modes['bold'][:3]+('bolditalic',) - CustomTTFonts.extend(font_modes.values()) - font_modes = init_new_font(familyName, name, font_dir) - - if (mode== 'normal') or (mode == 'regular') or (mode == 'medium') or (mode == 'book') or (mode == 'roman'): - font_modes['regular'] = (familyName, name, font_dir, 'regular') - elif (mode == 'italic') or (mode == 'oblique'): - font_modes['italic'] = (familyName, name, font_dir, 'italic') - elif mode == 'bold': - font_modes['bold'] = (familyName, name, font_dir, 'bold') - elif (mode == 'bolditalic') or (mode == 'boldoblique'): - font_modes['bolditalic'] = (familyName, name, font_dir, 'bolditalic') - last_family = familyName - - # add the last one - if font_modes: - if not font_modes['italic']: - font_modes['italic'] = font_modes['regular'][:3]+('italic',) - if not font_modes['bolditalic']: - font_modes['bolditalic'] = font_modes['bold'][:3]+('bolditalic',) - CustomTTFonts.extend(font_modes.values()) - - _fonts_cache['total_system_fonts'] = len(all_system_fonts) - - # remove duplicates - CustomTTFonts = sorted(list(set(CustomTTFonts))) - _fonts_cache['registered_fonts'] = sorted(list(set(_fonts_cache['registered_fonts']))) - return _fonts_cache['registered_fonts'] - def SetCustomFonts(rmldoc): """ Map some font names to the corresponding TTF fonts @@ -167,8 +109,6 @@ def SetCustomFonts(rmldoc): This function is called once per report, so it should avoid system-wide processing (cache it, instead). """ - if not _fonts_cache['registered_fonts']: - RegisterCustomFonts() for name, font, filename, mode in CustomTTFonts: if os.path.isabs(filename) and os.path.exists(filename): rmldoc.setTTFontMapping(name, font, filename, mode) diff --git a/openerp/service/server.py b/openerp/service/server.py index 7fa6dae0015..19457341b04 100644 --- a/openerp/service/server.py +++ b/openerp/service/server.py @@ -3,7 +3,6 @@ #----------------------------------------------------------- import datetime import errno -import fcntl import logging import os import os.path @@ -21,6 +20,11 @@ import time import traceback import werkzeug.serving + +try: + import fcntl +except ImportError: + pass try: from setproctitle import setproctitle except ImportError: