[FIX] merge from trunk and fix handling of view inheritance
main problem, view inheritance model field would use model from the root view (after following inherit_id links) rather than the base view (the requested one) -> with divergent models, it was possible for the requested view itself to never be returned. bzr revid: xmo@openerp.com-20131212134422-uxg6h21w1jhth9ow
This commit is contained in:
commit
0546993327
|
@ -39,7 +39,7 @@
|
||||||
<field name="city"></field>
|
<field name="city"></field>
|
||||||
<field name="zip"></field>
|
<field name="zip"></field>
|
||||||
<field name="phone"></field>
|
<field name="phone"></field>
|
||||||
<field name="email">info@yourcompany.example.com</field>
|
<field name="email">info@yourcompany.com</field>
|
||||||
<field name="website">www.yourcompany.com</field>
|
<field name="website">www.yourcompany.com</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
@ -68,10 +68,7 @@
|
||||||
<field name="name">Administrator</field>
|
<field name="name">Administrator</field>
|
||||||
<field name="company_id" ref="main_company"/>
|
<field name="company_id" ref="main_company"/>
|
||||||
<field name="customer" eval="False"/>
|
<field name="customer" eval="False"/>
|
||||||
<field name="email">admin@yourcompany.example.com</field>
|
<field name="email">admin@example.com</field>
|
||||||
<field name="city">Barchon</field>
|
|
||||||
<field name="zip">4671</field>
|
|
||||||
<field name="street">Rue de Heuseux 61</field>
|
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="res.users" id="base.user_root">
|
<record model="res.users" id="base.user_root">
|
||||||
|
@ -103,7 +100,6 @@ Administrator</field>
|
||||||
<field name="comment">Portal members have specific access rights (such as record rules and restricted menus).
|
<field name="comment">Portal members have specific access rights (such as record rules and restricted menus).
|
||||||
They usually do not belong to the usual OpenERP groups.</field>
|
They usually do not belong to the usual OpenERP groups.</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
A group dedicated to the public user only, making groups
|
A group dedicated to the public user only, making groups
|
||||||
restrictions more convenient.
|
restrictions more convenient.
|
||||||
|
@ -114,5 +110,25 @@ Administrator</field>
|
||||||
They usually do not belong to the usual OpenERP groups.</field>
|
They usually do not belong to the usual OpenERP groups.</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<!-- Basic fonts family included in PDF standart, will always be in the font list -->
|
||||||
|
<record model="res.font" id="base.font_helvetica">
|
||||||
|
<field name="name">Helvetica</field>
|
||||||
|
<field name="family">Helvetica</field>
|
||||||
|
<field name="path">/dev/null</field>
|
||||||
|
<field name="mode">all</field>
|
||||||
|
</record>
|
||||||
|
<record model="res.font" id="base.font_times">
|
||||||
|
<field name="name">Times</field>
|
||||||
|
<field name="family">Times</field>
|
||||||
|
<field name="path">/dev/null</field>
|
||||||
|
<field name="mode">all</field>
|
||||||
|
</record>
|
||||||
|
<record model="res.font" id="base.font_courier">
|
||||||
|
<field name="name">Courier</field>
|
||||||
|
<field name="family">Courier</field>
|
||||||
|
<field name="path">/dev/null</field>
|
||||||
|
<field name="mode">all</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -82,9 +82,8 @@ class ir_http(osv.AbstractModel):
|
||||||
# what if error in security.check()
|
# what if error in security.check()
|
||||||
# -> res_users.check()
|
# -> res_users.check()
|
||||||
# -> res_users.check_credentials()
|
# -> res_users.check_credentials()
|
||||||
except http.SessionExpiredException:
|
except Exception:
|
||||||
request.session.logout()
|
request.session.logout()
|
||||||
raise http.SessionExpiredException("Session expired for request %s" % request.httprequest)
|
|
||||||
getattr(self, "_auth_method_%s" % auth_method)()
|
getattr(self, "_auth_method_%s" % auth_method)()
|
||||||
return auth_method
|
return auth_method
|
||||||
|
|
||||||
|
|
|
@ -214,7 +214,6 @@ class view(osv.osv):
|
||||||
# Module init currently in progress, only consider views from
|
# Module init currently in progress, only consider views from
|
||||||
# modules whose code is already loaded
|
# modules whose code is already loaded
|
||||||
conditions.extend([
|
conditions.extend([
|
||||||
['model_ids.model', '=', 'ir.ui.view'],
|
|
||||||
'|',
|
'|',
|
||||||
['model_ids.module', 'in', tuple(self.pool._init_modules)],
|
['model_ids.module', 'in', tuple(self.pool._init_modules)],
|
||||||
['id', 'in', check_view_ids],
|
['id', 'in', check_view_ids],
|
||||||
|
@ -380,7 +379,7 @@ class view(osv.osv):
|
||||||
if context is None: context = {}
|
if context is None: context = {}
|
||||||
|
|
||||||
# if view_id is not a root view, climb back to the top.
|
# if view_id is not a root view, climb back to the top.
|
||||||
v = self.browse(cr, uid, view_id, context=context)
|
base = v = self.browse(cr, uid, view_id, context=context)
|
||||||
while v.inherit_id:
|
while v.inherit_id:
|
||||||
v = v.inherit_id
|
v = v.inherit_id
|
||||||
root_id = v.id
|
root_id = v.id
|
||||||
|
@ -401,7 +400,8 @@ class view(osv.osv):
|
||||||
})
|
})
|
||||||
|
|
||||||
# and apply inheritance
|
# and apply inheritance
|
||||||
arch = self.apply_view_inheritance(cr, uid, arch_tree, root_id, v.model, context=context)
|
arch = self.apply_view_inheritance(
|
||||||
|
cr, uid, arch_tree, root_id, base.model, context=context)
|
||||||
|
|
||||||
return dict(view, arch=etree.tostring(arch, encoding='utf-8'))
|
return dict(view, arch=etree.tostring(arch, encoding='utf-8'))
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
<!--logo-->
|
<!--logo-->
|
||||||
<fill color="black"/>
|
<fill color="black"/>
|
||||||
<stroke color="black"/>
|
<stroke color="black"/>
|
||||||
<setFont name="DejaVu Sans" size="8"/>
|
<setFont name="DejaVuSans" size="8"/>
|
||||||
<drawString x="1.3cm" y="19.5cm"><xsl:value-of select="//header-date"/></drawString>
|
<drawString x="1.3cm" y="19.5cm"><xsl:value-of select="//header-date"/></drawString>
|
||||||
<setFont name="DejaVu Sans Bold" size="10"/>
|
<setFont name="DejaVuSans-Bold" size="10"/>
|
||||||
<drawString x="13.8cm" y="19.5cm"><xsl:value-of select="//company"/></drawString>
|
<drawString x="13.8cm" y="19.5cm"><xsl:value-of select="//company"/></drawString>
|
||||||
<stroke color="#000000"/>
|
<stroke color="#000000"/>
|
||||||
<lines size="8">1.3cm 19.3cm 28.5cm 19.3cm</lines>
|
<lines size="8">1.3cm 19.3cm 28.5cm 19.3cm</lines>
|
||||||
|
|
|
@ -27,7 +27,6 @@ from openerp.osv import fields, osv
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
from openerp.tools.safe_eval import safe_eval as eval
|
from openerp.tools.safe_eval import safe_eval as eval
|
||||||
from openerp.tools import image_resize_image
|
from openerp.tools import image_resize_image
|
||||||
from openerp.report.render.rml2pdf import customfonts
|
|
||||||
|
|
||||||
class multi_company_default(osv.osv):
|
class multi_company_default(osv.osv):
|
||||||
"""
|
"""
|
||||||
|
@ -183,17 +182,20 @@ class res_company(osv.osv):
|
||||||
|
|
||||||
def onchange_font_name(self, cr, uid, ids, font, rml_header, rml_header2, rml_header3, context=None):
|
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. """
|
""" To change default header style of all <para> and drawstring. """
|
||||||
|
|
||||||
def _change_header(header,font):
|
def _change_header(header,font):
|
||||||
""" Replace default fontname use in header and setfont tag """
|
""" Replace default fontname use in header and setfont tag """
|
||||||
|
|
||||||
default_para = re.sub('fontName.?=.?".*"', 'fontName="%s"'% font,header)
|
default_para = re.sub('fontName.?=.?".*"', 'fontName="%s"'% font, header)
|
||||||
return re.sub('(<setFont.?name.?=.?)(".*?")(.)', '\g<1>"%s"\g<3>'% font,default_para)
|
return re.sub('(<setFont.?name.?=.?)(".*?")(.)', '\g<1>"%s"\g<3>'% font, default_para)
|
||||||
|
|
||||||
|
if not font:
|
||||||
|
return True
|
||||||
fontname = self.pool.get('res.font').browse(cr, uid, font, context=context).name
|
fontname = self.pool.get('res.font').browse(cr, uid, font, context=context).name
|
||||||
return {'value':{
|
return {'value':{
|
||||||
'rml_header': _change_header(rml_header,fontname),
|
'rml_header': _change_header(rml_header, fontname),
|
||||||
'rml_header2':_change_header(rml_header2,fontname),
|
'rml_header2':_change_header(rml_header2, fontname),
|
||||||
'rml_header3':_change_header(rml_header3,fontname)
|
'rml_header3':_change_header(rml_header3, fontname)
|
||||||
}}
|
}}
|
||||||
|
|
||||||
def on_change_country(self, cr, uid, ids, country_id, context=None):
|
def on_change_country(self, cr, uid, ids, country_id, context=None):
|
||||||
|
@ -294,12 +296,8 @@ class res_company(osv.osv):
|
||||||
|
|
||||||
def _get_font(self, cr, uid, ids):
|
def _get_font(self, cr, uid, ids):
|
||||||
font_obj = self.pool.get('res.font')
|
font_obj = self.pool.get('res.font')
|
||||||
res = font_obj.search(cr, uid, [('name', '=', 'Helvetica')], limit=1)
|
res = font_obj.search(cr, uid, [('family', '=', 'Helvetica'), ('mode', '=', 'all')], limit=1)
|
||||||
if res:
|
return res and res[0] or False
|
||||||
return res[0]
|
|
||||||
|
|
||||||
font_obj.init_no_scan(cr, uid)
|
|
||||||
return font_obj.search(cr, uid, [('name', '=', 'Helvetica')], limit=1)[0]
|
|
||||||
|
|
||||||
_header = """
|
_header = """
|
||||||
<header>
|
<header>
|
||||||
|
@ -307,20 +305,20 @@ class res_company(osv.osv):
|
||||||
<frame id="first" x1="28.0" y1="28.0" width="%s" height="%s"/>
|
<frame id="first" x1="28.0" y1="28.0" width="%s" height="%s"/>
|
||||||
<stylesheet>
|
<stylesheet>
|
||||||
<!-- Set here the default font to use for all <para> tags -->
|
<!-- Set here the default font to use for all <para> tags -->
|
||||||
<paraStyle name='Normal' fontName="DejaVu Sans"/>
|
<paraStyle name='Normal' fontName="DejaVuSans"/>
|
||||||
</stylesheet>
|
</stylesheet>
|
||||||
<pageGraphics>
|
<pageGraphics>
|
||||||
<fill color="black"/>
|
<fill color="black"/>
|
||||||
<stroke color="black"/>
|
<stroke color="black"/>
|
||||||
<setFont name="DejaVu Sans" size="8"/>
|
<setFont name="DejaVuSans" size="8"/>
|
||||||
<drawString x="%s" y="%s"> [[ formatLang(time.strftime("%%Y-%%m-%%d"), date=True) ]] [[ time.strftime("%%H:%%M") ]]</drawString>
|
<drawString x="%s" y="%s"> [[ formatLang(time.strftime("%%Y-%%m-%%d"), date=True) ]] [[ time.strftime("%%H:%%M") ]]</drawString>
|
||||||
<setFont name="DejaVu Sans Bold" size="10"/>
|
<setFont name="DejaVuSans-Bold" size="10"/>
|
||||||
<drawCentredString x="%s" y="%s">[[ company.partner_id.name ]]</drawCentredString>
|
<drawCentredString x="%s" y="%s">[[ company.partner_id.name ]]</drawCentredString>
|
||||||
<stroke color="#000000"/>
|
<stroke color="#000000"/>
|
||||||
<lines>%s</lines>
|
<lines>%s</lines>
|
||||||
<!-- Set here the default font to use for all <drawString> tags -->
|
<!-- Set here the default font to use for all <drawString> tags -->
|
||||||
<!-- don't forget to change the 2 other occurence of <setFont> above if needed -->
|
<!-- don't forget to change the 2 other occurence of <setFont> above if needed -->
|
||||||
<setFont name="DejaVu Sans" size="8"/>
|
<setFont name="DejaVuSans" size="8"/>
|
||||||
</pageGraphics>
|
</pageGraphics>
|
||||||
</pageTemplate>
|
</pageTemplate>
|
||||||
</header>"""
|
</header>"""
|
||||||
|
@ -345,13 +343,13 @@ class res_company(osv.osv):
|
||||||
<frame id="first" x1="1.3cm" y1="3.0cm" height="%s" width="19.0cm"/>
|
<frame id="first" x1="1.3cm" y1="3.0cm" height="%s" width="19.0cm"/>
|
||||||
<stylesheet>
|
<stylesheet>
|
||||||
<!-- Set here the default font to use for all <para> tags -->
|
<!-- Set here the default font to use for all <para> tags -->
|
||||||
<paraStyle name='Normal' fontName="DejaVu Sans"/>
|
<paraStyle name='Normal' fontName="DejaVuSans"/>
|
||||||
<paraStyle name="main_footer" fontSize="8.0" alignment="CENTER"/>
|
<paraStyle name="main_footer" fontSize="8.0" alignment="CENTER"/>
|
||||||
<paraStyle name="main_header" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
|
<paraStyle name="main_header" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
|
||||||
</stylesheet>
|
</stylesheet>
|
||||||
<pageGraphics>
|
<pageGraphics>
|
||||||
<!-- Set here the default font to use for all <drawString> tags -->
|
<!-- Set here the default font to use for all <drawString> tags -->
|
||||||
<setFont name="DejaVu Sans" size="8"/>
|
<setFont name="DejaVuSans" size="8"/>
|
||||||
<!-- You Logo - Change X,Y,Width and Height -->
|
<!-- You Logo - Change X,Y,Width and Height -->
|
||||||
<image x="1.3cm" y="%s" height="40.0" >[[ company.logo or removeParentNode('image') ]]</image>
|
<image x="1.3cm" y="%s" height="40.0" >[[ company.logo or removeParentNode('image') ]]</image>
|
||||||
<fill color="black"/>
|
<fill color="black"/>
|
||||||
|
@ -396,7 +394,7 @@ class res_company(osv.osv):
|
||||||
return {'value': {'rml_header': self._header_a4}}
|
return {'value': {'rml_header': self._header_a4}}
|
||||||
|
|
||||||
def act_discover_fonts(self, cr, uid, ids, context=None):
|
def act_discover_fonts(self, cr, uid, ids, context=None):
|
||||||
return self.pool.get("res.font").discover_fonts(cr, uid, ids, context)
|
return self.pool.get("res.font").font_scan(cr, uid, context=context)
|
||||||
|
|
||||||
_defaults = {
|
_defaults = {
|
||||||
'currency_id': _get_euro,
|
'currency_id': _get_euro,
|
||||||
|
|
|
@ -85,7 +85,7 @@
|
||||||
<label for="font" />
|
<label for="font" />
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<field name="font" class="oe_inline" colspan="2" on_change="onchange_font_name(font, rml_header, rml_header2, rml_header3)"/>
|
<field name="font" class="oe_inline" colspan="2" on_change="onchange_font_name(font, rml_header, rml_header2, rml_header3)" domain="[('mode', 'in', ('normal', 'regular', 'all', 'book'))]" />
|
||||||
<button string="(reload fonts)" name="act_discover_fonts" type="object" class="oe_link" colspan="1"/>
|
<button string="(reload fonts)" name="act_discover_fonts" type="object" class="oe_link" colspan="1"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
# OpenERP, Open Source Management Solution
|
# OpenERP, Open Source Management Solution
|
||||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
# Copyright (C) 2013 OpenERP SA (<http://openerp.com>).
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU Affero General Public License as
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
@ -20,6 +20,7 @@
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from reportlab.pdfbase import ttfonts
|
from reportlab.pdfbase import ttfonts
|
||||||
|
from openerp.modules.registry import RegistryManager
|
||||||
from openerp.osv import fields, osv
|
from openerp.osv import fields, osv
|
||||||
from openerp.report.render.rml2pdf import customfonts
|
from openerp.report.render.rml2pdf import customfonts
|
||||||
|
|
||||||
|
@ -40,57 +41,75 @@ _logger = logging.getLogger(__name__)
|
||||||
class res_font(osv.Model):
|
class res_font(osv.Model):
|
||||||
_name = "res.font"
|
_name = "res.font"
|
||||||
_description = 'Fonts available'
|
_description = 'Fonts available'
|
||||||
_order = 'name'
|
_order = 'family,name,id'
|
||||||
|
_rec_name = 'family'
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char("Name", required=True),
|
'family': fields.char("Font family", required=True),
|
||||||
|
'name': fields.char("Font Name", required=True),
|
||||||
|
'path': fields.char("Path", required=True),
|
||||||
|
'mode': fields.char("Mode", required=True),
|
||||||
}
|
}
|
||||||
|
|
||||||
_sql_constraints = [
|
_sql_constraints = [
|
||||||
('name_font_uniq', 'unique(name)', 'You can not register two fonts with the same name'),
|
('name_font_uniq', 'unique(family, name)', 'You can not register two fonts with the same name'),
|
||||||
]
|
]
|
||||||
|
|
||||||
def discover_fonts(self, cr, uid, ids, context=None):
|
def font_scan(self, cr, uid, lazy=False, context=None):
|
||||||
"""Scan fonts on the file system, add them to the list of known fonts
|
"""Action of loading fonts
|
||||||
and create font object for the new ones"""
|
In lazy mode will scan the filesystem only if there is no founts in the database and sync if no font in CustomTTFonts
|
||||||
customfonts.CustomTTFonts = customfonts.BaseCustomTTFonts
|
In not lazy mode will force scan filesystem and sync
|
||||||
|
"""
|
||||||
|
if lazy:
|
||||||
|
# lazy loading, scan only if no fonts in db
|
||||||
|
found_fonts_ids = self.search(cr, uid, [('path', '!=', '/dev/null')], context=context)
|
||||||
|
if not found_fonts_ids:
|
||||||
|
# no scan yet or no font found on the system, scan the filesystem
|
||||||
|
self._scan_disk(cr, uid, context=context)
|
||||||
|
elif len(customfonts.CustomTTFonts) == 0:
|
||||||
|
# CustomTTFonts list is empty
|
||||||
|
self._sync(cr, uid, context=context)
|
||||||
|
else:
|
||||||
|
self._scan_disk(cr, uid, context=context)
|
||||||
|
return True
|
||||||
|
|
||||||
found_fonts = {}
|
def _scan_disk(self, cr, uid, context=None):
|
||||||
|
"""Scan the file system and register the result in database"""
|
||||||
|
found_fonts = []
|
||||||
for font_path in customfonts.list_all_sysfonts():
|
for font_path in customfonts.list_all_sysfonts():
|
||||||
try:
|
try:
|
||||||
font = ttfonts.TTFontFile(font_path)
|
font = ttfonts.TTFontFile(font_path)
|
||||||
_logger.debug("Found font %s at %s", font.name, font_path)
|
_logger.debug("Found font %s at %s", font.name, font_path)
|
||||||
if not found_fonts.get(font.familyName):
|
found_fonts.append((font.familyName, font.name, font_path, font.styleName))
|
||||||
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:
|
except ttfonts.TTFError:
|
||||||
_logger.warning("Could not register Font %s", font_path)
|
_logger.warning("Could not register Font %s", font_path)
|
||||||
|
|
||||||
# add default PDF fonts
|
for family, name, path, mode in found_fonts:
|
||||||
for family in customfonts.BasePDFFonts:
|
if not self.search(cr, uid, [('family', '=', family), ('name', '=', name)], context=context):
|
||||||
if not found_fonts.get(family):
|
self.create(cr, uid, {
|
||||||
found_fonts[family] = {'name': family}
|
'family': family, 'name': name,
|
||||||
|
'path': path, 'mode': mode,
|
||||||
|
}, context=context)
|
||||||
|
|
||||||
# remove deleted fonts
|
# remove fonts not present on the disk anymore
|
||||||
existing_font_ids = self.search(cr, uid, [], context=context)
|
existing_font_names = [name for (family, name, path, mode) in found_fonts]
|
||||||
existing_font_names = []
|
inexistant_fonts = self.search(cr, uid, [('name', 'not in', existing_font_names), ('path', '!=', '/dev/null')], context=context)
|
||||||
for font in self.browse(cr, uid, existing_font_ids):
|
if inexistant_fonts:
|
||||||
existing_font_names.append(font.name)
|
self.unlink(cr, uid, inexistant_fonts, context=context)
|
||||||
if font.name not in found_fonts.keys():
|
|
||||||
self.unlink(cr, uid, font.id, context=context)
|
|
||||||
|
|
||||||
# add unknown fonts
|
RegistryManager.signal_caches_change(cr.dbname)
|
||||||
for family, vals in found_fonts.items():
|
self._sync(cr, uid, context=context)
|
||||||
if family not in existing_font_names:
|
|
||||||
self.create(cr, uid, vals, context=context)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def init_no_scan(self, cr, uid, context=None):
|
def _sync(self, cr, uid, context=None):
|
||||||
"""Add demo data for PDF fonts without scan (faster for db creation)"""
|
"""Set the customfonts.CustomTTFonts list to the content of the database"""
|
||||||
for font in customfonts.BasePDFFonts:
|
customfonts.CustomTTFonts = []
|
||||||
if not self.search(cr, uid, [('name', '=', font)], context=context):
|
found_fonts_ids = self.search(cr, uid, [('path', '!=', '/dev/null')], context=context)
|
||||||
self.create(cr, uid, {'name':font}, context=context)
|
for font in self.browse(cr, uid, found_fonts_ids, context=None):
|
||||||
return True
|
customfonts.CustomTTFonts.append((font.family, font.name, font.path, font.mode))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def clear_caches(self):
|
||||||
|
"""Force worker to resync at next report loading by setting an empty font list"""
|
||||||
|
customfonts.CustomTTFonts = []
|
||||||
|
return super(res_font, self).clear_caches()
|
|
@ -1,11 +1,11 @@
|
||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from lxml import etree as ET
|
|
||||||
from lxml.builder import E
|
|
||||||
import unittest2
|
import unittest2
|
||||||
|
|
||||||
|
from lxml import etree as ET
|
||||||
|
from lxml.builder import E
|
||||||
|
|
||||||
from openerp.tests import common
|
from openerp.tests import common
|
||||||
from openerp.osv.orm import except_orm
|
|
||||||
from openerp.tools import mute_logger
|
from openerp.tools import mute_logger
|
||||||
|
|
||||||
Field = E.field
|
Field = E.field
|
||||||
|
@ -431,7 +431,7 @@ class TestNoModel(common.TransactionCase):
|
||||||
|
|
||||||
class test_views(common.TransactionCase):
|
class test_views(common.TransactionCase):
|
||||||
|
|
||||||
def test_20_remove_unexisting_attribute(self):
|
def test_nonexistent_attribute_removal(self):
|
||||||
Views = self.registry('ir.ui.view')
|
Views = self.registry('ir.ui.view')
|
||||||
Views.create(self.cr, self.uid, {
|
Views.create(self.cr, self.uid, {
|
||||||
'name': 'Test View',
|
'name': 'Test View',
|
||||||
|
@ -456,7 +456,7 @@ class test_views(common.TransactionCase):
|
||||||
self.cr.execute(query, kw)
|
self.cr.execute(query, kw)
|
||||||
return self.cr.fetchone()[0]
|
return self.cr.fetchone()[0]
|
||||||
|
|
||||||
def test_10_validate_custom_views(self):
|
def test_custom_view_validation(self):
|
||||||
Views = self.registry('ir.ui.view')
|
Views = self.registry('ir.ui.view')
|
||||||
model = 'ir.actions.act_url'
|
model = 'ir.actions.act_url'
|
||||||
|
|
||||||
|
@ -488,3 +488,138 @@ class test_views(common.TransactionCase):
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
self.assertTrue(validate()) # inherited view
|
self.assertTrue(validate()) # inherited view
|
||||||
|
|
||||||
|
def test_view_inheritance(self):
|
||||||
|
Views = self.registry('ir.ui.view')
|
||||||
|
|
||||||
|
v1 = Views.create(self.cr, self.uid, {
|
||||||
|
'name': "bob",
|
||||||
|
'model': 'ir.ui.view',
|
||||||
|
'arch': """
|
||||||
|
<form string="Base title" version="7.0">
|
||||||
|
<separator string="separator" colspan="4"/>
|
||||||
|
<footer>
|
||||||
|
<button name="action_next" type="object" string="Next button"/>
|
||||||
|
or
|
||||||
|
<button string="Skip" special="cancel" />
|
||||||
|
</footer>
|
||||||
|
</form>
|
||||||
|
"""
|
||||||
|
})
|
||||||
|
v2 = Views.create(self.cr, self.uid, {
|
||||||
|
'name': "edmund",
|
||||||
|
'model': 'ir.ui.view',
|
||||||
|
'inherit_id': v1,
|
||||||
|
'arch': """
|
||||||
|
<data>
|
||||||
|
<form position="attributes" version="7.0">
|
||||||
|
<attribute name="string">Replacement title</attribute>
|
||||||
|
</form>
|
||||||
|
<footer position="replace">
|
||||||
|
<footer>
|
||||||
|
<button name="action_next" type="object" string="New button"/>
|
||||||
|
</footer>
|
||||||
|
</footer>
|
||||||
|
<separator string="separator" position="replace">
|
||||||
|
<p>Replacement data</p>
|
||||||
|
</separator>
|
||||||
|
</data>
|
||||||
|
"""
|
||||||
|
})
|
||||||
|
v3 = Views.create(self.cr, self.uid, {
|
||||||
|
'name': 'jake',
|
||||||
|
'model': 'ir.ui.view',
|
||||||
|
'inherit_id': v1,
|
||||||
|
'priority': 17,
|
||||||
|
'arch': """
|
||||||
|
<footer position="attributes">
|
||||||
|
<attribute name="thing">bob</attribute>
|
||||||
|
</footer>
|
||||||
|
"""
|
||||||
|
})
|
||||||
|
|
||||||
|
view = self.registry('ir.ui.view').fields_view_get(
|
||||||
|
self.cr, self.uid, v2, view_type='form', context={
|
||||||
|
# fucking what?
|
||||||
|
'check_view_ids': [v2, v3]
|
||||||
|
})
|
||||||
|
self.assertEqual(view['type'], 'form')
|
||||||
|
self.assertEqual(
|
||||||
|
ET.tostring(ET.fromstring(
|
||||||
|
view['arch'],
|
||||||
|
parser=ET.XMLParser(remove_blank_text=True)
|
||||||
|
)),
|
||||||
|
'<form string="Replacement title" version="7.0">'
|
||||||
|
'<p>Replacement data</p>'
|
||||||
|
'<footer thing="bob">'
|
||||||
|
'<button name="action_next" type="object" string="New button"/>'
|
||||||
|
'</footer>'
|
||||||
|
'</form>')
|
||||||
|
|
||||||
|
def test_view_inheritance_divergent_models(self):
|
||||||
|
Views = self.registry('ir.ui.view')
|
||||||
|
|
||||||
|
v1 = Views.create(self.cr, self.uid, {
|
||||||
|
'name': "bob",
|
||||||
|
'model': 'ir.ui.view.custom',
|
||||||
|
'arch': """
|
||||||
|
<form string="Base title" version="7.0">
|
||||||
|
<separator string="separator" colspan="4"/>
|
||||||
|
<footer>
|
||||||
|
<button name="action_next" type="object" string="Next button"/>
|
||||||
|
or
|
||||||
|
<button string="Skip" special="cancel" />
|
||||||
|
</footer>
|
||||||
|
</form>
|
||||||
|
"""
|
||||||
|
})
|
||||||
|
v2 = Views.create(self.cr, self.uid, {
|
||||||
|
'name': "edmund",
|
||||||
|
'model': 'ir.ui.view',
|
||||||
|
'inherit_id': v1,
|
||||||
|
'arch': """
|
||||||
|
<data>
|
||||||
|
<form position="attributes" version="7.0">
|
||||||
|
<attribute name="string">Replacement title</attribute>
|
||||||
|
</form>
|
||||||
|
<footer position="replace">
|
||||||
|
<footer>
|
||||||
|
<button name="action_next" type="object" string="New button"/>
|
||||||
|
</footer>
|
||||||
|
</footer>
|
||||||
|
<separator string="separator" position="replace">
|
||||||
|
<p>Replacement data</p>
|
||||||
|
</separator>
|
||||||
|
</data>
|
||||||
|
"""
|
||||||
|
})
|
||||||
|
v3 = Views.create(self.cr, self.uid, {
|
||||||
|
'name': 'jake',
|
||||||
|
'model': 'ir.ui.menu',
|
||||||
|
'inherit_id': v1,
|
||||||
|
'priority': 17,
|
||||||
|
'arch': """
|
||||||
|
<footer position="attributes">
|
||||||
|
<attribute name="thing">bob</attribute>
|
||||||
|
</footer>
|
||||||
|
"""
|
||||||
|
})
|
||||||
|
|
||||||
|
view = self.registry('ir.ui.view').fields_view_get(
|
||||||
|
self.cr, self.uid, v2, view_type='form', context={
|
||||||
|
# fucking what?
|
||||||
|
'check_view_ids': [v2, v3]
|
||||||
|
})
|
||||||
|
self.assertEqual(view['type'], 'form')
|
||||||
|
self.assertEqual(
|
||||||
|
ET.tostring(ET.fromstring(
|
||||||
|
view['arch'],
|
||||||
|
parser=ET.XMLParser(remove_blank_text=True)
|
||||||
|
)),
|
||||||
|
'<form string="Replacement title" version="7.0">'
|
||||||
|
'<p>Replacement data</p>'
|
||||||
|
'<footer>'
|
||||||
|
'<button name="action_next" type="object" string="New button"/>'
|
||||||
|
'</footer>'
|
||||||
|
'</form>')
|
||||||
|
|
||||||
|
|
|
@ -187,9 +187,16 @@ class WebRequest(object):
|
||||||
@service_model.check
|
@service_model.check
|
||||||
def checked_call(dbname, *a, **kw):
|
def checked_call(dbname, *a, **kw):
|
||||||
return self.func(*a, **kw)
|
return self.func(*a, **kw)
|
||||||
if self.db:
|
|
||||||
return checked_call(self.db, *args, **kwargs)
|
# FIXME: code and rollback management could be cleaned
|
||||||
return self.func(*args, **kwargs)
|
try:
|
||||||
|
if self.db:
|
||||||
|
return checked_call(self.db, *args, **kwargs)
|
||||||
|
return self.func(*args, **kwargs)
|
||||||
|
except Exception:
|
||||||
|
if self._cr:
|
||||||
|
self._cr.rollback()
|
||||||
|
raise
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def debug(self):
|
def debug(self):
|
||||||
|
@ -401,13 +408,9 @@ class HttpRequest(WebRequest):
|
||||||
self.params = params
|
self.params = params
|
||||||
|
|
||||||
def dispatch(self):
|
def dispatch(self):
|
||||||
try:
|
r = self._call_function(**self.params)
|
||||||
r = self._call_function(**self.params)
|
if not r:
|
||||||
except (werkzeug.exceptions.HTTPException), e:
|
r = werkzeug.wrappers.Response(status=204) # no content
|
||||||
r = e
|
|
||||||
else:
|
|
||||||
if not r:
|
|
||||||
r = werkzeug.wrappers.Response(status=204) # no content
|
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def make_response(self, data, headers=None, cookies=None):
|
def make_response(self, data, headers=None, cookies=None):
|
||||||
|
|
|
@ -24,8 +24,6 @@ import re
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
import openerp
|
|
||||||
|
|
||||||
import openerp
|
import openerp
|
||||||
import openerp.tools as tools
|
import openerp.tools as tools
|
||||||
import openerp.modules
|
import openerp.modules
|
||||||
|
@ -33,6 +31,9 @@ import print_xml
|
||||||
import render
|
import render
|
||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
|
from openerp import SUPERUSER_ID
|
||||||
|
from openerp.report.render.rml2pdf import customfonts
|
||||||
|
|
||||||
#
|
#
|
||||||
# coerce any type to a unicode string (to preserve non-ascii characters)
|
# coerce any type to a unicode string (to preserve non-ascii characters)
|
||||||
# and escape XML entities
|
# and escape XML entities
|
||||||
|
@ -91,13 +92,16 @@ class report_rml(report_int):
|
||||||
}
|
}
|
||||||
|
|
||||||
def create(self, cr, uid, ids, datas, context):
|
def create(self, cr, uid, ids, datas, context):
|
||||||
|
registry = openerp.registry(cr.dbname)
|
||||||
xml = self.create_xml(cr, uid, ids, datas, context)
|
xml = self.create_xml(cr, uid, ids, datas, context)
|
||||||
xml = tools.ustr(xml).encode('utf8')
|
xml = tools.ustr(xml).encode('utf8')
|
||||||
report_type = datas.get('report_type', 'pdf')
|
report_type = datas.get('report_type', 'pdf')
|
||||||
if report_type == 'raw':
|
if report_type == 'raw':
|
||||||
return xml, report_type
|
return xml, report_type
|
||||||
|
|
||||||
|
registry['res.font'].font_scan(cr, SUPERUSER_ID, lazy=True, context=context)
|
||||||
|
|
||||||
rml = self.create_rml(cr, xml, uid, context)
|
rml = self.create_rml(cr, xml, uid, context)
|
||||||
registry = openerp.registry(cr.dbname)
|
|
||||||
ir_actions_report_xml_obj = registry['ir.actions.report.xml']
|
ir_actions_report_xml_obj = registry['ir.actions.report.xml']
|
||||||
report_xml_ids = ir_actions_report_xml_obj.search(cr, uid, [('report_name', '=', self.name[7:])], context=context)
|
report_xml_ids = ir_actions_report_xml_obj.search(cr, uid, [('report_name', '=', self.name[7:])], context=context)
|
||||||
self.title = report_xml_ids and ir_actions_report_xml_obj.browse(cr,uid,report_xml_ids)[0].name or 'OpenERP Report'
|
self.title = report_xml_ids and ir_actions_report_xml_obj.browse(cr,uid,report_xml_ids)[0].name or 'OpenERP Report'
|
||||||
|
|
|
@ -21,10 +21,9 @@
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from reportlab import rl_config
|
from reportlab import rl_config
|
||||||
from reportlab.lib import fonts
|
|
||||||
from reportlab.pdfbase import pdfmetrics, ttfonts
|
|
||||||
import logging
|
import logging
|
||||||
import os,platform
|
import glob
|
||||||
|
import os
|
||||||
|
|
||||||
# .apidoc title: TTF Font Table
|
# .apidoc title: TTF Font Table
|
||||||
|
|
||||||
|
@ -39,35 +38,14 @@ and Ubuntu distros, we have to override the search path, too.
|
||||||
"""
|
"""
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Basic fonts family included in PDF standart, will always be in the font list
|
CustomTTFonts = []
|
||||||
BasePDFFonts = [
|
|
||||||
'Helvetica',
|
|
||||||
'Times',
|
|
||||||
'Courier'
|
|
||||||
]
|
|
||||||
|
|
||||||
# List of fonts found on the disk
|
|
||||||
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
|
# Search path for TTF files, in addition of rl_config.TTFSearchPath
|
||||||
TTFSearchPath = [
|
TTFSearchPath = [
|
||||||
'/usr/share/fonts/truetype', # SuSE
|
'/usr/share/fonts/truetype', # SuSE
|
||||||
'/usr/share/fonts/dejavu', '/usr/share/fonts/liberation', # Fedora, RHEL
|
'/usr/share/fonts/dejavu', '/usr/share/fonts/liberation', # Fedora, RHEL
|
||||||
'/usr/share/fonts/truetype/*','/usr/local/share/fonts' # Ubuntu,
|
'/usr/share/fonts/truetype/*','/usr/local/share/fonts' # Ubuntu,
|
||||||
'/usr/share/fonts/TTF/*', # at Mandriva/Mageia
|
'/usr/share/fonts/TTF/*', # Mandriva/Mageia
|
||||||
'/usr/share/fonts/TTF', # Arch Linux
|
'/usr/share/fonts/TTF', # Arch Linux
|
||||||
'/usr/lib/openoffice/share/fonts/truetype/',
|
'/usr/lib/openoffice/share/fonts/truetype/',
|
||||||
'~/.fonts',
|
'~/.fonts',
|
||||||
|
@ -95,10 +73,8 @@ def list_all_sysfonts():
|
||||||
# TTFOpenFile is not very good at it.
|
# TTFOpenFile is not very good at it.
|
||||||
searchpath = list(set(TTFSearchPath + rl_config.TTFSearchPath))
|
searchpath = list(set(TTFSearchPath + rl_config.TTFSearchPath))
|
||||||
for dirname in searchpath:
|
for dirname in searchpath:
|
||||||
dirname = os.path.expanduser(dirname)
|
for filename in glob.glob(os.path.join(os.path.expanduser(dirname), '*.[Tt][Tt][Ff]')):
|
||||||
if os.path.exists(dirname):
|
filepath.append(filename)
|
||||||
for filename in [x for x in os.listdir(dirname) if x.lower().endswith('.ttf')]:
|
|
||||||
filepath.append(os.path.join(dirname, filename))
|
|
||||||
return filepath
|
return filepath
|
||||||
|
|
||||||
def SetCustomFonts(rmldoc):
|
def SetCustomFonts(rmldoc):
|
||||||
|
@ -109,9 +85,9 @@ def SetCustomFonts(rmldoc):
|
||||||
This function is called once per report, so it should
|
This function is called once per report, so it should
|
||||||
avoid system-wide processing (cache it, instead).
|
avoid system-wide processing (cache it, instead).
|
||||||
"""
|
"""
|
||||||
for name, font, filename, mode in CustomTTFonts:
|
for family, font, filename, mode in CustomTTFonts:
|
||||||
if os.path.isabs(filename) and os.path.exists(filename):
|
if os.path.isabs(filename) and os.path.exists(filename):
|
||||||
rmldoc.setTTFontMapping(name, font, filename, mode)
|
rmldoc.setTTFontMapping(family, font, filename, mode)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -56,8 +56,11 @@ def select_fontname(fontname, default_fontname):
|
||||||
try:
|
try:
|
||||||
pdfmetrics.getFont(fontname)
|
pdfmetrics.getFont(fontname)
|
||||||
except Exception:
|
except Exception:
|
||||||
_logger.warning('Could not locate font %s, substituting default: %s',
|
addition = ""
|
||||||
fontname, default_fontname)
|
if " " in fontname:
|
||||||
|
addition = ". Your font contains spaces which is not valid in RML."
|
||||||
|
_logger.warning('Could not locate font %s, substituting default: %s%s',
|
||||||
|
fontname, default_fontname, addition)
|
||||||
fontname = default_fontname
|
fontname = default_fontname
|
||||||
return fontname
|
return fontname
|
||||||
|
|
||||||
|
@ -307,7 +310,7 @@ class _rml_doc(object):
|
||||||
addMapping(face, 0, 1, fontname) #italic
|
addMapping(face, 0, 1, fontname) #italic
|
||||||
addMapping(face, 1, 0, fontname) #bold
|
addMapping(face, 1, 0, fontname) #bold
|
||||||
addMapping(face, 1, 1, fontname) #italic and bold
|
addMapping(face, 1, 1, fontname) #italic and bold
|
||||||
elif (mode== 'normal') or (mode == 'regular'):
|
elif (mode== 'normal') or (mode == 'regular') or (mode == 'book'):
|
||||||
addMapping(face, 0, 0, fontname) #normal
|
addMapping(face, 0, 0, fontname) #normal
|
||||||
elif mode == 'italic':
|
elif mode == 'italic':
|
||||||
addMapping(face, 0, 1, fontname) #italic
|
addMapping(face, 0, 1, fontname) #italic
|
||||||
|
|
|
@ -34,6 +34,7 @@ import zipfile
|
||||||
import common
|
import common
|
||||||
|
|
||||||
import openerp
|
import openerp
|
||||||
|
from openerp import SUPERUSER_ID
|
||||||
from openerp.osv.fields import float as float_field, function as function_field, datetime as datetime_field
|
from openerp.osv.fields import float as float_field, function as function_field, datetime as datetime_field
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
|
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
|
||||||
|
@ -419,10 +420,13 @@ class report_sxw(report_rml, preprocess.report):
|
||||||
context = {}
|
context = {}
|
||||||
if self.internal_header:
|
if self.internal_header:
|
||||||
context.update(internal_header=self.internal_header)
|
context.update(internal_header=self.internal_header)
|
||||||
|
|
||||||
# skip osv.fields.sanitize_binary_value() because we want the raw bytes in all cases
|
# skip osv.fields.sanitize_binary_value() because we want the raw bytes in all cases
|
||||||
context.update(bin_raw=True)
|
context.update(bin_raw=True)
|
||||||
registry = openerp.registry(cr.dbname)
|
registry = openerp.registry(cr.dbname)
|
||||||
ir_obj = registry['ir.actions.report.xml']
|
ir_obj = registry['ir.actions.report.xml']
|
||||||
|
registry['res.font'].font_scan(cr, SUPERUSER_ID, lazy=True, context=context)
|
||||||
|
|
||||||
report_xml_ids = ir_obj.search(cr, uid,
|
report_xml_ids = ir_obj.search(cr, uid,
|
||||||
[('report_name', '=', self.name[7:])], context=context)
|
[('report_name', '=', self.name[7:])], context=context)
|
||||||
if report_xml_ids:
|
if report_xml_ids:
|
||||||
|
|
Loading…
Reference in New Issue