[ADD] report: support for dynamic fonts in report
search for TTF file on the system (in typical repositories) add font field on the company and config wizard, the chosen value will replace the fontName value by the new one bzr revid: mat@openerp.com-20131003141307-y6rsfooxepfgmofd
This commit is contained in:
commit
cd94736f1f
|
@ -20,14 +20,15 @@
|
|||
##############################################################################
|
||||
|
||||
import os
|
||||
|
||||
import re
|
||||
import openerp
|
||||
from openerp import SUPERUSER_ID, tools
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
from openerp.tools.safe_eval import safe_eval as eval
|
||||
from openerp.tools import image_resize_image
|
||||
|
||||
from openerp.report.render.rml2pdf import customfonts
|
||||
|
||||
class multi_company_default(osv.osv):
|
||||
"""
|
||||
Manage multi company default value
|
||||
|
@ -74,7 +75,7 @@ class res_company(osv.osv):
|
|||
_name = "res.company"
|
||||
_description = 'Companies'
|
||||
_order = 'name'
|
||||
|
||||
|
||||
def _get_address_data(self, cr, uid, ids, field_names, arg, context=None):
|
||||
""" Read the 'address' functional fields. """
|
||||
result = {}
|
||||
|
@ -108,9 +109,12 @@ class res_company(osv.osv):
|
|||
size = (180, None)
|
||||
result[record.id] = image_resize_image(record.partner_id.image, size)
|
||||
return result
|
||||
|
||||
|
||||
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'),
|
||||
|
@ -124,6 +128,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"),
|
||||
'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),
|
||||
|
@ -178,6 +183,21 @@ class res_company(osv.osv):
|
|||
if state_id:
|
||||
return {'value':{'country_id': self.pool.get('res.country.state').browse(cr, uid, state_id, context).country_id.id }}
|
||||
return {}
|
||||
|
||||
def onchange_font_name(self, cr, uid, ids, font, rml_header, rml_header2, rml_header3, context=None):
|
||||
""" To change default header style of all <para> and drawstring. """
|
||||
|
||||
def _change_header(header,font):
|
||||
""" Replace default fontname use in header and setfont tag """
|
||||
|
||||
default_para = re.sub('fontName.?=.?".*"', 'fontName="%s"'% font,header)
|
||||
return re.sub('(<setFont.?name.?=.?)(".*?")(.)', '\g<1>"%s"\g<3>'% font,default_para)
|
||||
return {'value':{
|
||||
'rml_header': _change_header(rml_header,font),
|
||||
'rml_header2':_change_header(rml_header2,font),
|
||||
'rml_header3':_change_header(rml_header3,font)
|
||||
}}
|
||||
|
||||
def on_change_country(self, cr, uid, ids, country_id, context=None):
|
||||
res = {'domain': {'state_id': []}}
|
||||
currency_id = self._get_euro(cr, uid, context=context)
|
||||
|
@ -374,7 +394,8 @@ class res_company(osv.osv):
|
|||
'rml_header':_get_header,
|
||||
'rml_header2': _header2,
|
||||
'rml_header3': _header3,
|
||||
'logo':_get_logo
|
||||
'logo':_get_logo,
|
||||
'font':'Helvetica',
|
||||
}
|
||||
|
||||
_constraints = [
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
<field name="custom_footer" on_change="onchange_footer(custom_footer, phone, fax, email, website, vat, company_registry, bank_ids)"/>
|
||||
<field name="rml_footer" attrs="{'invisible': [('custom_footer','=',False)]}"/>
|
||||
<field name="rml_footer_readonly" attrs="{'invisible': [('custom_footer','=',True)]}"/>
|
||||
<field name="font" on_change="onchange_font_name(font, rml_header, rml_header2, rml_header3)"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Header/Footer" groups="base.group_no_one">
|
||||
|
|
|
@ -20,14 +20,13 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
import glob
|
||||
import logging
|
||||
import os
|
||||
import platform
|
||||
from reportlab import rl_config
|
||||
from reportlab.lib import fonts
|
||||
from reportlab.pdfbase import pdfmetrics, ttfonts
|
||||
import logging
|
||||
import os,platform
|
||||
|
||||
from openerp.tools import config
|
||||
|
||||
# .apidoc title: TTF Font Table
|
||||
|
||||
"""This module allows the mapping of some system-available TTF fonts to
|
||||
the reportlab engine.
|
||||
|
@ -38,103 +37,127 @@ 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__)
|
||||
|
||||
CustomTTFonts = [ ('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'),
|
||||
('Times-Roman',"Liberation Serif", "LiberationSerif-Regular.ttf", 'normal'),
|
||||
('Times-Roman',"Liberation Serif Bold", "LiberationSerif-Bold.ttf", 'bold'),
|
||||
('Times-Roman',"Liberation Serif Italic", "LiberationSerif-Italic.ttf", 'italic'),
|
||||
('Times-Roman',"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'),
|
||||
|
||||
# Sun-ExtA can be downloaded from http://okuc.net/SunWb/
|
||||
('Sun-ExtA',"Sun-ExtA", "Sun-ExtA.ttf", 'normal'),
|
||||
# Basic fonts familly included in PDF standart, will always be in the font list
|
||||
BasePDFFonts = [
|
||||
('Helvetica', 'Helvetica'),
|
||||
('Times', 'Times'),
|
||||
('Courier', 'Courier'),
|
||||
]
|
||||
|
||||
# List of fonts found on the disk
|
||||
CustomTTFonts = []
|
||||
|
||||
TTFSearchPath_Linux = [
|
||||
# Search path for TTF files, in addition of rl_config.TTFSearchPath
|
||||
TTFSearchPath = [
|
||||
'/usr/share/fonts/truetype', # SuSE
|
||||
'/usr/share/fonts/dejavu', '/usr/share/fonts/liberation', # Fedora, RHEL
|
||||
'/usr/share/fonts/truetype/*', # Ubuntu,
|
||||
'/usr/share/fonts/truetype/*','/usr/local/share/fonts' # Ubuntu,
|
||||
'/usr/share/fonts/TTF/*', # at Mandriva/Mageia
|
||||
'/usr/share/fonts/TTF', # Arch Linux
|
||||
]
|
||||
'/usr/lib/openoffice/share/fonts/truetype/',
|
||||
'~/.fonts',
|
||||
'~/.local/share/fonts',
|
||||
|
||||
TTFSearchPath_Windows = [
|
||||
'c:/winnt/fonts',
|
||||
'c:/windows/fonts'
|
||||
]
|
||||
|
||||
TTFSearchPath_Darwin = [
|
||||
#mac os X - from
|
||||
#http://developer.apple.com/technotes/tn/tn2024.html
|
||||
# mac os X - from
|
||||
# http://developer.apple.com/technotes/tn/tn2024.html
|
||||
'~/Library/Fonts',
|
||||
'/Library/Fonts',
|
||||
'/Network/Library/Fonts',
|
||||
'/System/Library/Fonts',
|
||||
]
|
||||
|
||||
TTFSearchPathMap = {
|
||||
'Darwin': TTFSearchPath_Darwin,
|
||||
'Windows': TTFSearchPath_Windows,
|
||||
'Linux': TTFSearchPath_Linux,
|
||||
}
|
||||
# windows
|
||||
'c:/winnt/fonts',
|
||||
'c:/windows/fonts'
|
||||
]
|
||||
|
||||
# ----- The code below is less distro-specific, please avoid editing! -------
|
||||
__foundFonts = None
|
||||
|
||||
def FindCustomFonts():
|
||||
"""Fill the __foundFonts list with those filenames, whose fonts
|
||||
can be found in the reportlab ttf font path.
|
||||
|
||||
This process needs only be done once per loading of this module,
|
||||
it is cached. But, if the system admin adds some font in the
|
||||
meanwhile, the server must be restarted eventually.
|
||||
def all_sysfonts_list():
|
||||
"""
|
||||
dirpath = []
|
||||
global __foundFonts
|
||||
__foundFonts = {}
|
||||
searchpath = []
|
||||
|
||||
if config.get('fonts_search_path'):
|
||||
searchpath += map(str.strip, config.get('fonts_search_path').split(','))
|
||||
|
||||
local_platform = platform.system()
|
||||
if local_platform in TTFSearchPathMap:
|
||||
searchpath += TTFSearchPathMap[local_platform]
|
||||
|
||||
# Append the original search path of reportlab (at the end)
|
||||
searchpath += rl_config.TTFSearchPath
|
||||
This function returns list of font directories of system.
|
||||
"""
|
||||
filepath = []
|
||||
|
||||
# Perform the search for font files ourselves, as reportlab's
|
||||
# TTFOpenFile is not very good at it.
|
||||
for dirglob in searchpath:
|
||||
dirglob = os.path.expanduser(dirglob)
|
||||
for dirname in glob.iglob(dirglob):
|
||||
abp = os.path.abspath(dirname)
|
||||
if os.path.isdir(abp):
|
||||
dirpath.append(abp)
|
||||
searchpath = list(set(TTFSearchPath + rl_config.TTFSearchPath))
|
||||
for dirname in searchpath:
|
||||
dirname = os.path.expanduser(dirname)
|
||||
if os.path.exists(dirname):
|
||||
for filename in [x for x in os.listdir(dirname) if x.lower().endswith('.ttf')]:
|
||||
filepath.append(os.path.join(dirname, filename))
|
||||
return filepath
|
||||
|
||||
for k, (name, font, filename, mode) in enumerate(CustomTTFonts):
|
||||
if filename in __foundFonts:
|
||||
continue
|
||||
for d in dirpath:
|
||||
abs_filename = os.path.join(d, filename)
|
||||
if os.path.exists(abs_filename):
|
||||
_logger.debug("Found font %s at %s", filename, abs_filename)
|
||||
__foundFonts[filename] = abs_filename
|
||||
break
|
||||
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
|
||||
|
@ -144,16 +167,11 @@ def SetCustomFonts(rmldoc):
|
|||
This function is called once per report, so it should
|
||||
avoid system-wide processing (cache it, instead).
|
||||
"""
|
||||
global __foundFonts
|
||||
if __foundFonts is None:
|
||||
FindCustomFonts()
|
||||
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)
|
||||
elif filename in __foundFonts:
|
||||
rmldoc.setTTFontMapping(name, font, __foundFonts[filename], mode)
|
||||
return True
|
||||
|
||||
#eof
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
Loading…
Reference in New Issue