Further pylint improvements to document generators

This commit is contained in:
Nick Hall 2016-06-04 18:29:10 +01:00
parent 36f5a6addc
commit a3fd7c06be
5 changed files with 839 additions and 897 deletions

View File

@ -27,27 +27,8 @@
# Python modules # Python modules
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
from math import radians from math import radians
#------------------------------------------------------------------------
#
# Gramps modules
#
#------------------------------------------------------------------------
from gramps.gen.plug.docgen import PAPER_PORTRAIT
import gramps.plugins.lib.libcairodoc as libcairodoc
from gramps.gen.errors import UnavailableError
#import constfunc
#------------------------------------------------------------------------
#
# Set up logging
#
#------------------------------------------------------------------------
import logging import logging
log = logging.getLogger(".GtkPrint")
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@ -61,6 +42,23 @@ try: # the Gramps-Connect server has no DISPLAY
except: except:
pass pass
#------------------------------------------------------------------------
#
# Gramps modules
#
#------------------------------------------------------------------------
from gramps.gen.plug.docgen import PAPER_PORTRAIT
import gramps.plugins.lib.libcairodoc as libcairodoc
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
#------------------------------------------------------------------------
#
# Set up logging
#
#------------------------------------------------------------------------
LOG = logging.getLogger(".GtkPrint")
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
# Constants # Constants
@ -128,7 +126,7 @@ def paperstyle_to_pagesetup(paper_style):
# are handled as custom format, because we are not intelligent enough. # are handled as custom format, because we are not intelligent enough.
if gramps_paper_name in gramps_to_gtk: if gramps_paper_name in gramps_to_gtk:
paper_size = Gtk.PaperSize.new(name=gramps_to_gtk[gramps_paper_name]) paper_size = Gtk.PaperSize.new(name=gramps_to_gtk[gramps_paper_name])
log.debug("Selected paper size: %s" % gramps_to_gtk[gramps_paper_name]) LOG.debug("Selected paper size: %s", gramps_to_gtk[gramps_paper_name])
else: else:
if paper_style.get_orientation() == PAPER_PORTRAIT: if paper_style.get_orientation() == PAPER_PORTRAIT:
paper_width = gramps_paper_size.get_width() * 10 paper_width = gramps_paper_size.get_width() * 10
@ -139,7 +137,7 @@ def paperstyle_to_pagesetup(paper_style):
paper_size = Gtk.PaperSize.new_custom("custom", "Custom Size", paper_size = Gtk.PaperSize.new_custom("custom", "Custom Size",
paper_width, paper_height, paper_width, paper_height,
Gtk.Unit.MM) Gtk.Unit.MM)
log.debug("Selected paper size: (%f,%f)" % (paper_width, paper_height)) LOG.debug("Selected paper size: (%f,%f)", paper_width, paper_height)
page_setup = Gtk.PageSetup() page_setup = Gtk.PageSetup()
page_setup.set_paper_size(paper_size) page_setup.set_paper_size(paper_size)
@ -234,7 +232,7 @@ class PrintPreview:
##""" ##"""
##if page_no >= len(self._page_numbers): ##if page_no >= len(self._page_numbers):
##log.debug("Page number %d doesn't exist." % page_no) ##LOG.debug("Page number %d doesn't exist." % page_no)
##page_no = 0 ##page_no = 0
##if page_no not in self._page_surfaces: ##if page_no not in self._page_surfaces:

View File

@ -32,28 +32,34 @@
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
# python modules # Python modules
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
from bisect import bisect from bisect import bisect
import re, os, sys import re
import os
import logging import logging
_LOG = logging.getLogger(".latexdoc")
#----------------------------------------------------------------------- -
#
# gramps modules
#
#------------------------------------------------------------------------
from gramps.gen.plug.docgen import BaseDoc, TextDoc, PAPER_LANDSCAPE, FONT_SANS_SERIF, URL_PATTERN
from gramps.gen.plug.docbackend import DocBackend
HAVE_PIL = False
try: try:
from PIL import Image from PIL import Image
HAVE_PIL = True HAVE_PIL = True
except: except ImportError:
HAVE_PIL = False
#----------------------------------------------------------------------- -
#
# Gramps modules
#
#------------------------------------------------------------------------
from gramps.gen.plug.docgen import (BaseDoc, TextDoc, PAPER_LANDSCAPE,
FONT_SANS_SERIF, URL_PATTERN)
from gramps.gen.plug.docbackend import DocBackend
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
_LOG = logging.getLogger(".latexdoc")
if not HAVE_PIL:
_LOG.warning(_("PIL (Python Imaging Library) not loaded. " _LOG.warning(_("PIL (Python Imaging Library) not loaded. "
"Production of jpg images from non-jpg images " "Production of jpg images from non-jpg images "
"in LaTeX documents will not be available. " "in LaTeX documents will not be available. "
@ -435,8 +441,8 @@ def map_font_size(fontsize):
TBLFMT_PAT = re.compile(r'({\|?)l(\|?})') TBLFMT_PAT = re.compile(r'({\|?)l(\|?})')
# constants for routing in table construction: # constants for routing in table construction:
(CELL_BEG, CELL_TEXT, CELL_END, (CELL_BEG, CELL_TEXT, CELL_END, ROW_BEG, ROW_END, TAB_BEG,
ROW_BEG, ROW_END, TAB_BEG, TAB_END) = list(range(7)) TAB_END) = list(range(7))
FIRST_ROW, SUBSEQ_ROW = list(range(2)) FIRST_ROW, SUBSEQ_ROW = list(range(2))
@ -489,18 +495,18 @@ def str_incr(str_counter):
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
class Tab_Cell: class TabCell:
def __init__(self, colchar, span, head, content): def __init__(self, colchar, span, head, content):
self.colchar = colchar self.colchar = colchar
self.span = span self.span = span
self.head = head self.head = head
self.content = content self.content = content
class Tab_Row: class TabRow:
def __init__(self): def __init__(self):
self.cells = [] self.cells = []
self.tail = '' self.tail = ''
self.addit = '' # for: \\hline, \\cline{} self.addit = '' # for: \\hline, \\cline{}
class Tab_Mem: class TabMem:
def __init__(self, head): def __init__(self, head):
self.head = head self.head = head
self.tail = '' self.tail = ''
@ -513,8 +519,7 @@ class Tab_Mem:
#------------------------------------------------------------------------ #------------------------------------------------------------------------
def latexescape(text): def latexescape(text):
""" """
change text in text that latex shows correctly Escape the following special characters: & $ % # _ { }
special characters: \& \$ \% \# \_ \{ \}
""" """
text = text.replace('&', '\\&') text = text.replace('&', '\\&')
text = text.replace('$', '\\$') text = text.replace('$', '\\$')
@ -529,25 +534,16 @@ def latexescape(text):
def latexescapeverbatim(text): def latexescapeverbatim(text):
""" """
change text in text that latex shows correctly respecting whitespace Escape special characters and also make sure that LaTeX respects whitespace
special characters: \& \$ \% \# \_ \{ \} and newlines correctly.
Now also make sure space and newline is respected
""" """
text = text.replace('&', '\\&') text = latexescape(text)
text = text.replace('$', '\\$')
text = text.replace('%', '\\%')
text = text.replace('#', '\\#')
text = text.replace('_', '\\_')
text = text.replace('{', '\\{')
text = text.replace('}', '\\}')
text = text.replace(' ', '\\ ') text = text.replace(' ', '\\ ')
text = text.replace('\n', '~\\newline \n') text = text.replace('\n', '~\\newline \n')
#spaces at begin are normally ignored, make sure they are not. #spaces at begin are normally ignored, make sure they are not.
#due to above a space at begin is now \newline\n\ #due to above a space at begin is now \newline\n\
text = text.replace('\\newline\n\\ ', text = text.replace('\\newline\n\\ ',
'\\newline\n\\hspace*{0.1\\grbaseindent}\\ ') '\\newline\n\\hspace*{0.1\\grbaseindent}\\ ')
# replace character unknown to LaTeX
text = text.replace('','$\\longrightarrow$')
return text return text
#------------------------------------------------------------------------ #------------------------------------------------------------------------
@ -634,13 +630,13 @@ class TexFont:
if style: if style:
self.font_beg = style.font_beg self.font_beg = style.font_beg
self.font_end = style.font_end self.font_end = style.font_end
self.leftIndent = style.left_indent self.left_indent = style.left_indent
self.firstLineIndent = style.firstLineIndent self.first_line_indent = style.first_line_indent
else: else:
self.font_beg = "" self.font_beg = ""
self.font_end = "" self.font_end = ""
self.leftIndent = "" self.left_indent = ""
self.firstLineIndent = "" self.first_line_indent = ""
#------------------------------------------------------------------ #------------------------------------------------------------------
@ -691,9 +687,9 @@ class LaTeXDoc(BaseDoc, TextDoc):
if span > 1: # phantom columns prior to multicolumns if span > 1: # phantom columns prior to multicolumns
for col in range(self.curcol - span, self.curcol - 1): for col in range(self.curcol - span, self.curcol - 1):
col_char = get_charform(col) col_char = get_charform(col)
phantom = Tab_Cell(col_char, 0, '', '') phantom = TabCell(col_char, 0, '', '')
self.tabrow.cells.append(phantom) self.tabrow.cells.append(phantom)
self.tabcell = Tab_Cell(self.curcol_char, span, text, '') self.tabcell = TabCell(self.curcol_char, span, text, '')
elif tab_state == CELL_TEXT: elif tab_state == CELL_TEXT:
self.textmem.append(text) self.textmem.append(text)
elif tab_state == CELL_END: # text == '' elif tab_state == CELL_END: # text == ''
@ -707,7 +703,7 @@ class LaTeXDoc(BaseDoc, TextDoc):
self.tabrow.cells.append(self.tabcell) self.tabrow.cells.append(self.tabcell)
self.textmem = [] self.textmem = []
elif tab_state == ROW_BEG: elif tab_state == ROW_BEG:
self.tabrow = Tab_Row() self.tabrow = TabRow()
elif tab_state == ROW_END: elif tab_state == ROW_END:
self.tabrow.addit = text # text: \\hline, \\cline{} self.tabrow.addit = text # text: \\hline, \\cline{}
self.tabrow.tail = ''.join(self.textmem) # \\\\ row-termination self.tabrow.tail = ''.join(self.textmem) # \\\\ row-termination
@ -718,7 +714,7 @@ class LaTeXDoc(BaseDoc, TextDoc):
elif tab_state == TAB_BEG: # text: \\begin{longtable}[l]{ elif tab_state == TAB_BEG: # text: \\begin{longtable}[l]{
self._backend.write(''.join(('\\grinittab{\\textwidth}{', self._backend.write(''.join(('\\grinittab{\\textwidth}{',
repr(1.0/self.numcols), '}%\n'))) repr(1.0/self.numcols), '}%\n')))
self.tabmem = Tab_Mem(text) self.tabmem = TabMem(text)
elif tab_state == TAB_END: # text: \\end{longtable} elif tab_state == TAB_END: # text: \\end{longtable}
self.tabmem.tail = text self.tabmem.tail = text
@ -740,8 +736,8 @@ class LaTeXDoc(BaseDoc, TextDoc):
# extract cell.contents # extract cell.contents
bare_contents = [cell.content.strip(SEPARATION_PAT).replace( bare_contents = [cell.content.strip(SEPARATION_PAT).replace(
'\n', '').split(SEPARATION_PAT) '\n', '').split(SEPARATION_PAT) for cell in self.tabrow.cells]
for cell in self.tabrow.cells]
# mk equal length & transpose # mk equal length & transpose
num_new_rows = max([len(mult_row_cont) num_new_rows = max([len(mult_row_cont)
for mult_row_cont in bare_contents]) for mult_row_cont in bare_contents])
@ -759,15 +755,18 @@ class LaTeXDoc(BaseDoc, TextDoc):
self.pict = transp_cont[0][-1] self.pict = transp_cont[0][-1]
last_cell -= 1 last_cell -= 1
self.numcols -= 1 self.numcols -= 1
self._backend.write(''.join(('\\addtolength{\\grtabwidth}{-', self._backend.write(''.join(
repr(self.pict_width), '\\grbaseindent -2\\tabcolsep}%\n'))) ('\\addtolength{\\grtabwidth}{-',
repr(self.pict_width),
'\\grbaseindent -2\\tabcolsep}%\n')))
self.pict_in_table = False self.pict_in_table = False
# new row-col structure # new row-col structure
for row in range(num_new_rows): for row in range(num_new_rows):
new_row = Tab_Row() new_row = TabRow()
for i in range(first_cell, last_cell): for i in range(first_cell, last_cell):
new_cell = Tab_Cell(get_charform(i + first_cell), new_cell = TabCell(
get_charform(i + first_cell),
self.tabrow.cells[i].span, self.tabrow.cells[i].head, self.tabrow.cells[i].span, self.tabrow.cells[i].head,
transp_cont[row][i + first_cell]) transp_cont[row][i + first_cell])
new_row.cells.append(new_cell) new_row.cells.append(new_cell)
@ -796,43 +795,50 @@ class LaTeXDoc(BaseDoc, TextDoc):
if cell.span == 0: if cell.span == 0:
continue continue
if cell.content.startswith('\\grmkpicture'): if cell.content.startswith('\\grmkpicture'):
self._backend.write(''.join(('\\setlength{\\grpictsize}{', self._backend.write(
''.join(('\\setlength{\\grpictsize}{',
self.pict_width, '\\grbaseindent}%\n'))) self.pict_width, '\\grbaseindent}%\n')))
else: else:
for part in cell.content.split(SEPARATION_PAT): for part in cell.content.split(SEPARATION_PAT):
self._backend.write(''.join(('\\grtextneedwidth{', self._backend.write(
part, '}%\n'))) ''.join(('\\grtextneedwidth{', part, '}%\n')))
row.cells[col_num].content = cell.content.replace( row.cells[col_num].content = cell.content.replace(
SEPARATION_PAT, '~\\newline \n') SEPARATION_PAT, '~\\newline \n')
if cell.span == 1: if cell.span == 1:
self._backend.write(''.join(('\\grsetreqfull%\n'))) self._backend.write(''.join(('\\grsetreqfull%\n')))
elif cell.span > 1: elif cell.span > 1:
self._backend.write(''.join(('\\grsetreqpart{\\grcolbeg', self._backend.write(
get_charform(get_numform(cell.colchar) - cell.span +1), ''.join(('\\grsetreqpart{\\grcolbeg',
get_charform(get_numform(cell.colchar) -
cell.span +1),
'}%\n'))) '}%\n')))
self._backend.write(''.join(('\\grcolsfirstfix', self._backend.write(
''.join(('\\grcolsfirstfix',
' {\\grcolbeg', col_char, '}{\\grtempwidth', col_char, ' {\\grcolbeg', col_char, '}{\\grtempwidth', col_char,
'}{\\grfinalwidth', col_char, '}{\\grpictreq', col_char, '}{\\grfinalwidth', col_char, '}{\\grpictreq',
'}{\\grtextreq', col_char, '}%\n'))) col_char, '}{\\grtextreq', col_char, '}%\n')))
self._backend.write(''.join(('\\grdividelength%\n'))) self._backend.write(''.join(('\\grdividelength%\n')))
for col_char in tabcol_chars: for col_char in tabcol_chars:
self._backend.write(''.join(('\\grcolssecondfix', self._backend.write(
''.join(('\\grcolssecondfix',
' {\\grcolbeg', col_char, '}{\\grtempwidth', col_char, ' {\\grcolbeg', col_char, '}{\\grtempwidth', col_char,
'}{\\grfinalwidth', col_char, '}{\\grpictreq', col_char, '}{\\grfinalwidth', col_char, '}{\\grpictreq',
'}%\n'))) col_char, '}%\n')))
self._backend.write(''.join(('\\grdividelength%\n'))) self._backend.write(''.join(('\\grdividelength%\n')))
for col_char in tabcol_chars: for col_char in tabcol_chars:
self._backend.write(''.join(('\\grcolsthirdfix', self._backend.write(
''.join(('\\grcolsthirdfix',
' {\\grcolbeg', col_char, '}{\\grtempwidth', col_char, ' {\\grcolbeg', col_char, '}{\\grtempwidth', col_char,
'}{\\grfinalwidth', col_char, '}%\n'))) '}{\\grfinalwidth', col_char, '}%\n')))
self._backend.write(''.join(('\\grdividelength%\n'))) self._backend.write(''.join(('\\grdividelength%\n')))
for col_char in tabcol_chars: for col_char in tabcol_chars:
self._backend.write(''.join(('\\grcolsfourthfix', self._backend.write(
''.join(('\\grcolsfourthfix',
' {\\grcolbeg', col_char, '}{\\grtempwidth', col_char, ' {\\grcolbeg', col_char, '}{\\grtempwidth', col_char,
'}{\\grfinalwidth', col_char, '}%\n'))) '}{\\grfinalwidth', col_char, '}%\n')))
@ -841,10 +847,11 @@ class LaTeXDoc(BaseDoc, TextDoc):
for cell in row.cells: for cell in row.cells:
if cell.span > 1: if cell.span > 1:
multcol_alph_id = next(self.multcol_alph_counter) multcol_alph_id = next(self.multcol_alph_counter)
self._backend.write(''.join(('\\grgetspanwidth{', self._backend.write(
''.join(('\\grgetspanwidth{',
'\\grspanwidth', multcol_alph_id, '\\grspanwidth', multcol_alph_id,
'}{\\grcolbeg', get_charform(get_numform(cell.colchar)- '}{\\grcolbeg', get_charform(
cell.span + 1), get_numform(cell.colchar)- cell.span + 1),
'}{\\grcolbeg', cell.colchar, '}{\\grcolbeg', cell.colchar,
'}{\\grtempwidth', cell.colchar, '}{\\grtempwidth', cell.colchar,
'}%\n'))) '}%\n')))
@ -852,7 +859,8 @@ class LaTeXDoc(BaseDoc, TextDoc):
def write_table(self): def write_table(self):
# Choosing RaggedRight (with hyphenation) in table and # Choosing RaggedRight (with hyphenation) in table and
# provide manually adjusting of column widths # provide manually adjusting of column widths
self._backend.write(''.join(( self._backend.write(
''.join((
'%\n', self.pict, '%\n', self.pict,
'%\n%\n', '%\n%\n',
'% ==> Comment out one of the two lines ', '% ==> Comment out one of the two lines ',
@ -862,13 +870,15 @@ class LaTeXDoc(BaseDoc, TextDoc):
'% ==> You may add pos or neg values ', '% ==> You may add pos or neg values ',
'to the following ', repr(self.numcols), ' column widths %\n'))) 'to the following ', repr(self.numcols), ' column widths %\n')))
for col_num in range(self.numcols): for col_num in range(self.numcols):
self._backend.write(''.join(('\\addtolength{\\grtempwidth', self._backend.write(
''.join(('\\addtolength{\\grtempwidth',
get_charform(col_num), '}{+0.0cm}%\n'))) get_charform(col_num), '}{+0.0cm}%\n')))
self._backend.write('% === %\n') self._backend.write('% === %\n')
# adjust & open table': # adjust & open table':
if self.pict: if self.pict:
self._backend.write(''.join(('%\n\\vspace{\\grtabprepos}%\n', self._backend.write(
''.join(('%\n\\vspace{\\grtabprepos}%\n',
'\\setlength{\\grtabprepos}{0ex}%\n'))) '\\setlength{\\grtabprepos}{0ex}%\n')))
self.pict = '' self.pict = ''
self._backend.write(''.join(self.tabmem.head)) self._backend.write(''.join(self.tabmem.head))
@ -915,7 +925,8 @@ class LaTeXDoc(BaseDoc, TextDoc):
else: else:
cell_width = ''.join(('\\grspanwidth', cell_width = ''.join(('\\grspanwidth',
next(self.multcol_alph_counter))) next(self.multcol_alph_counter)))
splitting.append(''.join(('\\grtabpgbreak{', cell.head, '}{', splitting.append(
''.join(('\\grtabpgbreak{', cell.head, '}{',
cell_width, '}{', add_vdots, '}{+2ex}%\n'))) cell_width, '}{', add_vdots, '}{+2ex}%\n')))
return ''.join((' & '.join(splitting), '%\n', row.tail)) return ''.join((' & '.join(splitting), '%\n', row.tail))
@ -929,8 +940,9 @@ class LaTeXDoc(BaseDoc, TextDoc):
else: else:
cell_width = ''.join(('\\grspanwidth', cell_width = ''.join(('\\grspanwidth',
next(self.multcol_alph_counter))) next(self.multcol_alph_counter)))
complete.append(''.join(('\\grcolpart{%\n ', cell.head, complete.append(
'}{%\n', cell_width, '}{%\n ', cell.content, '%\n}%\n'))) ''.join(('\\grcolpart{%\n ', cell.head, '}{%\n', cell_width,
'}{%\n ', cell.content, '%\n}%\n')))
return ''.join((' & '.join(complete), '%\n', row.tail, row.addit)) return ''.join((' & '.join(complete), '%\n', row.tail, row.addit))
# --------------------------------------------------------------------- # ---------------------------------------------------------------------
@ -1016,8 +1028,8 @@ class LaTeXDoc(BaseDoc, TextDoc):
left = style.get_left_margin() left = style.get_left_margin()
first = style.get_first_indent() + left first = style.get_first_indent() + left
thisstyle.leftIndent = left thisstyle.left_indent = left
thisstyle.firstLineIndent = first thisstyle.first_line_indent = first
self.latexstyle[style_name] = thisstyle self.latexstyle[style_name] = thisstyle
@ -1045,10 +1057,10 @@ class LaTeXDoc(BaseDoc, TextDoc):
self.fbeg = ltxstyle.font_beg self.fbeg = ltxstyle.font_beg
self.fend = ltxstyle.font_end self.fend = ltxstyle.font_end
self.indent = ltxstyle.leftIndent self.indent = ltxstyle.left_indent
self.FLindent = ltxstyle.firstLineIndent self.first_line_indent = ltxstyle.first_line_indent
if self.indent == 0: if self.indent == 0:
self.indent = self.FLindent self.indent = self.first_line_indent
# For additional vertical space beneath title line(s) # For additional vertical space beneath title line(s)
# i.e. when the first centering ended: # i.e. when the first centering ended:
@ -1059,8 +1071,8 @@ class LaTeXDoc(BaseDoc, TextDoc):
self.in_multrow_cell = True self.in_multrow_cell = True
else: else:
if leader: if leader:
self._backend.write(''.join(('\\grprepleader{', leader, self._backend.write(
'}%\n'))) ''.join(('\\grprepleader{', leader, '}%\n')))
else: else:
self._backend.write('\\grprepnoleader%\n') self._backend.write('\\grprepnoleader%\n')
@ -1070,8 +1082,9 @@ class LaTeXDoc(BaseDoc, TextDoc):
# there another value might be choosen. # there another value might be choosen.
# ------------------------------------------------------------------- # -------------------------------------------------------------------
if self.indent is not None: if self.indent is not None:
self._backend.write(''.join(('\\grminpghead{', self._backend.write(
repr(self.indent), '}{', repr(self.pict_width), '}%\n'))) ''.join(('\\grminpghead{', repr(self.indent), '}{',
repr(self.pict_width), '}%\n')))
self.fix_indent = True self.fix_indent = True
if leader is not None and not self.in_list: if leader is not None and not self.in_list:
@ -1171,10 +1184,10 @@ class LaTeXDoc(BaseDoc, TextDoc):
# values imported here are used for test '==1' and '!=0'. To get # values imported here are used for test '==1' and '!=0'. To get
# local boolean values the tests are now transfered to the import lines # local boolean values the tests are now transfered to the import lines
# ------------------------------------------------------------------ # ------------------------------------------------------------------
self.lborder = 1 == self.cstyle.get_left_border() self.lborder = self.cstyle.get_left_border() == 1
self.rborder = 1 == self.cstyle.get_right_border() self.rborder = self.cstyle.get_right_border() == 1
self.bborder = 1 == self.cstyle.get_bottom_border() self.bborder = self.cstyle.get_bottom_border() == 1
self.tborder = 0 != self.cstyle.get_top_border() self.tborder = self.cstyle.get_top_border() != 0
# self.llist not needed any longer. # self.llist not needed any longer.
# now column widths are arranged in self.calc_latex_widths() # now column widths are arranged in self.calc_latex_widths()
@ -1207,8 +1220,7 @@ class LaTeXDoc(BaseDoc, TextDoc):
self.emit('', CELL_END) self.emit('', CELL_END)
def add_media(self, infile, pos, x, y, alt='', def add_media(self, infile, pos, x, y, alt='', style_name=None, crop=None):
style_name=None, crop=None):
"""Add photo to report""" """Add photo to report"""
outfile = os.path.splitext(infile)[0] outfile = os.path.splitext(infile)[0]
pictname = latexescape(os.path.split(outfile)[1]) pictname = latexescape(os.path.split(outfile)[1])
@ -1219,9 +1231,9 @@ class LaTeXDoc(BaseDoc, TextDoc):
try: try:
curr_img = Image.open(infile) curr_img = Image.open(infile)
curr_img.save(outfile) curr_img.save(outfile)
px, py = curr_img.size width, height = curr_img.size
if py > px: if height > width:
y = y*py/px y = y*height/width
except IOError: except IOError:
self.emit(''.join(('%\n *** Error: cannot convert ', infile, self.emit(''.join(('%\n *** Error: cannot convert ', infile,
'\n *** to ', outfile, '\n *** to ', outfile,
@ -1245,7 +1257,7 @@ class LaTeXDoc(BaseDoc, TextDoc):
text = '' text = ''
text = latexescape(text) text = latexescape(text)
if links == True: if links is True:
text = re.sub(URL_PATTERN, _CLICKABLE, text) text = re.sub(URL_PATTERN, _CLICKABLE, text)
#hard coded replace of the underline used for missing names/data #hard coded replace of the underline used for missing names/data
@ -1277,7 +1289,7 @@ class LaTeXDoc(BaseDoc, TextDoc):
markuptext = self._backend.add_markup_from_styled(text, s_tags) markuptext = self._backend.add_markup_from_styled(text, s_tags)
if links == True: if links is True:
markuptext = re.sub(URL_PATTERN, _CLICKABLE, markuptext) markuptext = re.sub(URL_PATTERN, _CLICKABLE, markuptext)
markuptext = self._backend.add_markup_from_styled(text, s_tags) markuptext = self._backend.add_markup_from_styled(text, s_tags)

View File

@ -28,34 +28,6 @@
ODFDoc : used to generate Open Office Document ODFDoc : used to generate Open Office Document
""" """
#-------------------------------------------------------------------------
#
# pylint : disable messages ...
#
#-------------------------------------------------------------------------
# disable-msg=C0302 # Too many lines in module
# pylint: disable-msg=C0302
# disable-msg # Regular expression which should only match
# pylint: disable-msg=C0103
# disable-msg=R0902 # Too many instance attributes
# pylint: disable-msg=R0902
# disable-msg=R0904 # Too many public methods
# pylint: disable-msg=R0904
# disable-msg=R0912 # Too many branches
# pylint: disable-msg=R0912
# disable-msg=R0913 # Too many arguments
# pylint: disable-msg=R0913
# disable-msg=R0914 # Too many local variables
# pylint: disable-msg=R0914
# disable-msg=R0915 # Too many statements
# pylint: disable-msg=R0915
# warnings :
# disable-msg=W0613 # Unused argument
# pylint: disable-msg=W0613
# errors :
# disable-msg=E1101 # has no member
# pylint: disable-msg=E1101
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# Standard Python Modules # Standard Python Modules
@ -66,19 +38,20 @@ from hashlib import md5
import zipfile import zipfile
import time import time
from io import StringIO from io import StringIO
from math import pi, cos, sin, degrees, radians from math import cos, sin, radians
from xml.sax.saxutils import escape from xml.sax.saxutils import escape
import re
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# Gramps modules # Gramps modules
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
from gramps.gen.plug.docgen import (BaseDoc, TextDoc, DrawDoc, graphicstyle, from gramps.gen.plug.docgen import (
FONT_SANS_SERIF, SOLID, PAPER_PORTRAIT, BaseDoc, TextDoc, DrawDoc, graphicstyle, FONT_SANS_SERIF, SOLID,
INDEX_TYPE_TOC, PARA_ALIGN_CENTER, PARA_ALIGN_LEFT, PAPER_PORTRAIT, INDEX_TYPE_TOC, PARA_ALIGN_CENTER, PARA_ALIGN_LEFT,
INDEX_TYPE_ALP, PARA_ALIGN_RIGHT, URL_PATTERN, INDEX_TYPE_ALP, PARA_ALIGN_RIGHT, URL_PATTERN, LOCAL_HYPERLINK,
LOCAL_HYPERLINK, LOCAL_TARGET) LOCAL_TARGET)
from gramps.gen.plug.docgen.fontscale import string_width from gramps.gen.plug.docgen.fontscale import string_width
from gramps.plugins.lib.libodfbackend import OdfBackend from gramps.plugins.lib.libodfbackend import OdfBackend
from gramps.gen.const import PROGRAM_NAME, URL_HOMEPAGE from gramps.gen.const import PROGRAM_NAME, URL_HOMEPAGE
@ -96,9 +69,9 @@ from gramps.gen.errors import ReportError
from gramps.gen.const import GRAMPS_LOCALE as glocale from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext _ = glocale.translation.gettext
_apptype = 'application/vnd.oasis.opendocument.text' APP_TYPE = 'application/vnd.oasis.opendocument.text'
_esc_map = { ESC_MAP = {
'\x1a' : '', '\x1a' : '',
'\x0c' : '', '\x0c' : '',
'\n' : '<text:line-break/>', '\n' : '<text:line-break/>',
@ -110,9 +83,8 @@ _esc_map = {
# regexp for Styled Notes ... # regexp for Styled Notes ...
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
import re
# Hyphen is added because it is used to replace spaces in the font name # Hyphen is added because it is used to replace spaces in the font name
NewStyle = re.compile('style-name="([a-zA-Z0-9]*)__([#a-zA-Z0-9 -]*)__">') NEW_STYLE = re.compile('style-name="([a-zA-Z0-9]*)__([#a-zA-Z0-9 -]*)__">')
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@ -457,15 +429,15 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.new_cell = 0 self.new_cell = 0
self.page = 0 self.page = 0
self.first_page = 1 self.first_page = 1
self.StyleList_notes = [] # styles to create depending on styled notes. self.stylelist_notes = [] # styles to create for styled notes.
self.StyleList_photos = [] # styles to create depending on clipped images. self.stylelist_photos = [] # styles to create for clipped images.
def open(self, filename): def open(self, filename):
""" """
Open the new document Open the new document
""" """
t = time.localtime(time.time()) now = time.localtime(time.time())
self.time = "%04d-%02d-%02dT%02d:%02d:%02d" % t[:6] self.time = "%04d-%02d-%02dT%02d:%02d:%02d" % now[:6]
self.filename = filename self.filename = filename
if not filename.endswith("odt"): if not filename.endswith("odt"):
@ -482,7 +454,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
Create the document header Create the document header
""" """
assert (not self.init_called) assert not self.init_called
self.init_called = True self.init_called = True
wrt = self.cntnt.write wrt = self.cntnt.write
wrt1, wrt2 = self.cntnt1.write, self.cntnt2.write wrt1, wrt2 = self.cntnt1.write, self.cntnt2.write
@ -490,8 +462,8 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.lang = glocale.lang self.lang = glocale.lang
self.lang = self.lang.replace('_', '-') if self.lang else "en-US" self.lang = self.lang.replace('_', '-') if self.lang else "en-US"
self.StyleList_notes = [] # styles to create depending on styled notes. self.stylelist_notes = [] # styles to create depending on styled notes.
wrt1('<?xml version="1.0" encoding="UTF-8"?>\n' wrt1('<?xml version="1.0" encoding="UTF-8"?>\n' +
'<office:document-content\n' + '<office:document-content\n' +
_XMLNS + _XMLNS +
'office:version="1.0">\n' + 'office:version="1.0">\n' +
@ -500,8 +472,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
wrt1('<office:font-face-decls>\n' + wrt1('<office:font-face-decls>\n' +
_FONTS _FONTS
) )
wrt2( wrt2('</office:font-face-decls>\n' +
'</office:font-face-decls>\n' +
'<office:automatic-styles>\n' + '<office:automatic-styles>\n' +
_AUTOMATIC_STYLES _AUTOMATIC_STYLES
) )
@ -510,16 +481,14 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
for style_name in styles.get_draw_style_names(): for style_name in styles.get_draw_style_names():
style = styles.get_draw_style(style_name) style = styles.get_draw_style(style_name)
wrt( wrt('<style:style ' +
'<style:style ' +
'style:name="%s" ' % style_name + 'style:name="%s" ' % style_name +
'style:family="graphic">\n' 'style:family="graphic">\n'
'<style:graphic-properties ' '<style:graphic-properties '
) )
if style.get_line_width(): if style.get_line_width():
wrt( wrt('svg:stroke-width="%.2f" '
'svg:stroke-width="%.2f" '
% (style.get_line_width()*10) + % (style.get_line_width()*10) +
'draw:marker-start="" ' 'draw:marker-start="" '
'draw:marker-start-width="0.0" ' 'draw:marker-start-width="0.0" '
@ -529,17 +498,16 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
) )
if style.get_line_style() != SOLID: if style.get_line_style() != SOLID:
#wrt('svg:fill-color="#ff0000" ') #wrt('svg:fill-color="#ff0000" ')
wrt('draw:stroke="dash" draw:stroke-dash="gramps_%s" ' % style.get_dash_style_name()) wrt('draw:stroke="dash" draw:stroke-dash="gramps_%s" ' %
style.get_dash_style_name())
else: else:
wrt('draw:stroke="solid" ') wrt('draw:stroke="solid" ')
else: else:
wrt( wrt('draw:stroke="none" '
'draw:stroke="none" '
'draw:stroke-color="#000000" ' 'draw:stroke-color="#000000" '
) )
wrt( wrt('svg:fill-color="#%02x%02x%02x" '
'svg:fill-color="#%02x%02x%02x" '
% style.get_color() + % style.get_color() +
'draw:fill-color="#%02x%02x%02x" ' 'draw:fill-color="#%02x%02x%02x" '
% style.get_fill_color() + % style.get_fill_color() +
@ -612,24 +580,20 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
elif align == PARA_ALIGN_RIGHT: elif align == PARA_ALIGN_RIGHT:
wrt('fo:text-align="end" ') wrt('fo:text-align="end" ')
elif align == PARA_ALIGN_CENTER: elif align == PARA_ALIGN_CENTER:
wrt( wrt('fo:text-align="center" '
'fo:text-align="center" '
'style:justify-single-word="false" ' 'style:justify-single-word="false" '
) )
else: else:
wrt( wrt('fo:text-align="justify" '
'fo:text-align="justify" '
'style:justify-single-word="false" ' 'style:justify-single-word="false" '
) )
font = style.get_font() font = style.get_font()
wrt('style:font-name="%s" ' % wrt('style:font-name="%s" ' %
("Arial" ("Arial" if font.get_type_face() == FONT_SANS_SERIF
if font.get_type_face() == FONT_SANS_SERIF else else "Times New Roman")
"Times New Roman")
) )
wrt( wrt('fo:font-size="%.2fpt" ' % font.get_size() +
'fo:font-size="%.2fpt" ' % font.get_size() +
'style:font-size-asian="%.2fpt" ' % font.get_size() + 'style:font-size-asian="%.2fpt" ' % font.get_size() +
'fo:color="#%02x%02x%02x" ' % font.get_color() 'fo:color="#%02x%02x%02x" ' % font.get_color()
) )
@ -639,13 +603,11 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
if font.get_italic(): if font.get_italic():
wrt('fo:font-style="italic" ') wrt('fo:font-style="italic" ')
if font.get_underline(): if font.get_underline():
wrt( wrt('style:text-underline="single" '
'style:text-underline="single" '
'style:text-underline-color="font-color" ' 'style:text-underline-color="font-color" '
) )
wrt( wrt('fo:text-indent="%.2fcm"\n' % style.get_first_indent() +
'fo:text-indent="%.2fcm"\n' % style.get_first_indent() +
'fo:margin-right="%.2fcm"\n' % style.get_right_margin() + 'fo:margin-right="%.2fcm"\n' % style.get_right_margin() +
'fo:margin-left="%.2fcm"\n' % style.get_left_margin() + 'fo:margin-left="%.2fcm"\n' % style.get_left_margin() +
'fo:margin-top="%.2fcm"\n' % style.get_top_margin() + 'fo:margin-top="%.2fcm"\n' % style.get_top_margin() +
@ -654,8 +616,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
'</style:style>\n' '</style:style>\n'
) )
wrt( wrt('<style:style style:name="F%s" ' % style_name +
'<style:style style:name="F%s" ' % style_name +
'style:family="text">\n' + 'style:family="text">\n' +
'<style:text-properties ' '<style:text-properties '
) )
@ -666,16 +627,14 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
elif align == PARA_ALIGN_RIGHT: elif align == PARA_ALIGN_RIGHT:
wrt('fo:text-align="end" ') wrt('fo:text-align="end" ')
elif align == PARA_ALIGN_CENTER: elif align == PARA_ALIGN_CENTER:
wrt( wrt('fo:text-align="center" '
'fo:text-align="center" '
'style:justify-single-word="false" ' 'style:justify-single-word="false" '
) )
font = style.get_font() font = style.get_font()
wrt('style:font-name="%s" ' % wrt('style:font-name="%s" ' %
("Arial" ("Arial" if font.get_type_face() == FONT_SANS_SERIF
if font.get_type_face() == FONT_SANS_SERIF else else "Times New Roman")
"Times New Roman")
) )
color = font.get_color() color = font.get_color()
@ -685,8 +644,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
if font.get_italic(): if font.get_italic():
wrt('fo:font-style="italic" ') wrt('fo:font-style="italic" ')
wrt( wrt('fo:font-size="%.2fpt" ' % font.get_size() +
'fo:font-size="%.2fpt" ' % font.get_size() +
'style:font-size-asian="%.2fpt"/> ' % font.get_size() + 'style:font-size-asian="%.2fpt"/> ' % font.get_size() +
'</style:style>\n' '</style:style>\n'
) )
@ -695,8 +653,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
style = styles.get_table_style(style_name) style = styles.get_table_style(style_name)
table_width = float(self.get_usable_width()) table_width = float(self.get_usable_width())
table_width_str = "%.2f" % table_width table_width_str = "%.2f" % table_width
wrt( wrt('<style:style style:name="%s" ' % style_name +
'<style:style style:name="%s" ' % style_name +
'style:family="table-properties">\n' 'style:family="table-properties">\n'
'<style:table-properties-properties ' + '<style:table-properties-properties ' +
'style:width="%scm" ' % table_width_str + 'style:width="%scm" ' % table_width_str +
@ -707,8 +664,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
for col in range(0, min(style.get_columns(), 50)): for col in range(0, min(style.get_columns(), 50)):
width = table_width * float(style.get_column_width(col) / 100.0) width = table_width * float(style.get_column_width(col) / 100.0)
width_str = "%.4f" % width width_str = "%.4f" % width
wrt( wrt('<style:style style:name="%s.%s" '
'<style:style style:name="%s.%s" '
% (style_name, chr(ord('A')+col)) + % (style_name, chr(ord('A')+col)) +
'style:family="table-column">' + 'style:family="table-column">' +
'<style:table-column-properties ' + '<style:table-column-properties ' +
@ -718,38 +674,32 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
for cell in styles.get_cell_style_names(): for cell in styles.get_cell_style_names():
cell_style = styles.get_cell_style(cell) cell_style = styles.get_cell_style(cell)
wrt( wrt('<style:style style:name="%s" ' % cell +
'<style:style style:name="%s" ' % cell +
'style:family="table-cell">\n' + 'style:family="table-cell">\n' +
'<style:table-cell-properties' + '<style:table-cell-properties' +
' fo:padding="%.2fcm"' % cell_style.get_padding() ' fo:padding="%.2fcm"' % cell_style.get_padding()
) )
wrt(' fo:border-top="%s"' % wrt(' fo:border-top="%s"' %
("0.002cm solid #000000" ("0.002cm solid #000000" if cell_style.get_top_border()
if cell_style.get_top_border() else else "none")
"none")
) )
wrt(' fo:border-bottom="%s"' % wrt(' fo:border-bottom="%s"' %
("0.002cm solid #000000" ("0.002cm solid #000000" if cell_style.get_bottom_border()
if cell_style.get_bottom_border() else else "none")
"none")
) )
wrt(' fo:border-left="%s"' % wrt(' fo:border-left="%s"' %
("0.002cm solid #000000" ("0.002cm solid #000000" if cell_style.get_left_border()
if cell_style.get_left_border() else else "none")
"none")
) )
wrt(' fo:border-right="%s"' % wrt(' fo:border-right="%s"' %
("0.002cm solid #000000" ("0.002cm solid #000000" if cell_style.get_right_border()
if cell_style.get_right_border() else else "none")
"none")
) )
wrt( wrt('/>\n'
'/>\n'
'</style:style>\n' '</style:style>\n'
) )
@ -789,7 +739,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
The content.xml file is closed. The content.xml file is closed.
""" """
self.cntntx = StringIO() self.cntntx = StringIO()
self.StyleList_notes = self.uniq(self.StyleList_notes) self.stylelist_notes = self.uniq(self.stylelist_notes)
self.add_styled_notes_fonts() self.add_styled_notes_fonts()
self.add_styled_notes_styles() self.add_styled_notes_styles()
self.add_styled_photo_styles() self.add_styled_photo_styles()
@ -823,12 +773,11 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
""" """
# Need to add new font for styled notes here. # Need to add new font for styled notes here.
wrt1 = self.cntnt1.write wrt1 = self.cntnt1.write
for style in self.StyleList_notes: for style in self.stylelist_notes:
if style[1] == "FontFace": if style[1] == "FontFace":
# Restore any spaces that were replaced by hyphens in # Restore any spaces that were replaced by hyphens in
# libodfbackend # libodfbackend
wrt1( wrt1('<style:font-face ' +
'<style:font-face ' +
' style:name="%s"\n' % style[2].replace("-", " ") + ' style:name="%s"\n' % style[2].replace("-", " ") +
' svg:font-family="&apos;%s&apos;"\n' % ' svg:font-family="&apos;%s&apos;"\n' %
style[2].replace("-", " ") + style[2].replace("-", " ") +
@ -841,10 +790,9 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
""" """
# Need to add new style for styled notes here. # Need to add new style for styled notes here.
wrt2 = self.cntnt2.write wrt2 = self.cntnt2.write
for style in self.StyleList_notes: for style in self.stylelist_notes:
if style[1] == "FontSize": if style[1] == "FontSize":
wrt2( wrt2('<style:style ' +
'<style:style ' +
'style:name="FontSize__%s__"\n' % style[2] + 'style:name="FontSize__%s__"\n' % style[2] +
' style:family="text">\n' + ' style:family="text">\n' +
' <style:text-properties\n' + ' <style:text-properties\n' +
@ -857,8 +805,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
elif style[1] == "FontColor": elif style[1] == "FontColor":
# Restore the hash at the start that was removed by # Restore the hash at the start that was removed by
# libodfbackend # libodfbackend
wrt2( wrt2('<style:style ' +
'<style:style ' +
'style:name="FontColor__%s__"\n' % style[2] + 'style:name="FontColor__%s__"\n' % style[2] +
' style:family="text">\n' + ' style:family="text">\n' +
' <style:text-properties\n' + ' <style:text-properties\n' +
@ -867,8 +814,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
) )
elif style[1] == "FontHighlight": elif style[1] == "FontHighlight":
wrt2( wrt2('<style:style ' +
'<style:style ' +
'style:name="FontHighlight__%s__"\n' % style[2] + 'style:name="FontHighlight__%s__"\n' % style[2] +
' style:family="text">\n' + ' style:family="text">\n' +
' <style:text-properties\n' + ' <style:text-properties\n' +
@ -879,8 +825,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
elif style[1] == "FontFace": elif style[1] == "FontFace":
# Restore any spaces that were replaced by hyphens in # Restore any spaces that were replaced by hyphens in
# libodfbackend # libodfbackend
wrt2( wrt2('<style:style ' +
'<style:style ' +
'style:name="FontFace__%s__"\n' % style[2] + 'style:name="FontFace__%s__"\n' % style[2] +
' style:family="text">\n' + ' style:family="text">\n' +
' <style:text-properties\n' + ' <style:text-properties\n' +
@ -895,10 +840,9 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
Add the new styles for clipped images in the automatic-styles section. Add the new styles for clipped images in the automatic-styles section.
""" """
wrt2 = self.cntnt2.write wrt2 = self.cntnt2.write
for style in self.StyleList_photos: for style in self.stylelist_photos:
if style[0] == "Left": if style[0] == "Left":
wrt2( wrt2('<style:style ' +
'<style:style ' +
'style:name="Left_%s" ' % str(style[1]) + 'style:name="Left_%s" ' % str(style[1]) +
'style:family="graphic" ' + 'style:family="graphic" ' +
'style:parent-style-name="photo">' + 'style:parent-style-name="photo">' +
@ -925,8 +869,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
'</style:style>\n' '</style:style>\n'
) )
elif style[0] == "Right": elif style[0] == "Right":
wrt2( wrt2('<style:style ' +
'<style:style ' +
'style:name="Right_%s" ' % str(style[1]) + 'style:name="Right_%s" ' % str(style[1]) +
'style:family="graphic" ' + 'style:family="graphic" ' +
'style:parent-style-name="photo">' + 'style:parent-style-name="photo">' +
@ -953,8 +896,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
'</style:style>\n' '</style:style>\n'
) )
elif style[0] == "Single": elif style[0] == "Single":
wrt2( wrt2('<style:style ' +
'<style:style ' +
'style:name="Single_%s" ' % str(style[1]) + 'style:name="Single_%s" ' % str(style[1]) +
'style:family="graphic" ' + 'style:family="graphic" ' +
'style:parent-style-name="photo">' + 'style:parent-style-name="photo">' +
@ -974,8 +916,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
'</style:style>\n' '</style:style>\n'
) )
else: else:
wrt2( wrt2('<style:style ' +
'<style:style ' +
'style:name="Row_%s" ' % str(style[1]) + 'style:name="Row_%s" ' % str(style[1]) +
'style:family="graphic" ' + 'style:family="graphic" ' +
'style:parent-style-name="Graphics">' + 'style:parent-style-name="Graphics">' +
@ -998,7 +939,8 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
'</style:style>\n' '</style:style>\n'
) )
def add_media(self, file_name, pos, x_cm, y_cm, alt='', style_name=None, crop=None): def add_media(self, file_name, pos, x_cm, y_cm, alt='', style_name=None,
crop=None):
""" """
Add multi-media documents : photos Add multi-media documents : photos
""" """
@ -1015,7 +957,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
odf_name = md5(file_name_hash).hexdigest() + extension odf_name = md5(file_name_hash).hexdigest() + extension
media_list_item = (file_name, odf_name) media_list_item = (file_name, odf_name)
if not media_list_item in self.media_list: if media_list_item not in self.media_list:
self.media_list.append(media_list_item) self.media_list.append(media_list_item)
base = escape(os.path.basename(file_name)) base = escape(os.path.basename(file_name))
@ -1027,11 +969,11 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
pos = pos.title() if pos in ['left', 'right', 'single'] else 'Row' pos = pos.title() if pos in ['left', 'right', 'single'] else 'Row'
if crop: if crop:
(start_x, start_y, end_x, end_y (start_x, start_y,
) = crop_percentage_to_subpixel(x, y, crop) end_x, end_y) = crop_percentage_to_subpixel(x, y, crop)
# Need to keep the ratio intact, otherwise scaled images look stretched # Need to keep the ratio intact, otherwise scaled images look
# if the dimensions aren't close in size # stretched if the dimensions aren't close in size
(act_width, act_height) = image_actual_size( (act_width, act_height) = image_actual_size(
x_cm, y_cm, int(end_x-start_x), int(end_y-start_y) x_cm, y_cm, int(end_x-start_x), int(end_y-start_y)
) )
@ -1045,7 +987,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
bottom = (y - end_y)/dpi[1] bottom = (y - end_y)/dpi[1]
crop = (top, right, bottom, left) crop = (top, right, bottom, left)
self.StyleList_photos.append( self.stylelist_photos.append(
[pos, crop] [pos, crop]
) )
@ -1174,12 +1116,12 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
""" """
self.cntnt.write('</text:span>') self.cntnt.write('</text:span>')
def _add_zip(self, zfile, name, data, t): def _add_zip(self, zfile, name, data, date_time):
""" """
Add a zip file to an archive Add a zip file to an archive
""" """
zipinfo = zipfile.ZipInfo(name) zipinfo = zipfile.ZipInfo(name)
zipinfo.date_time = t zipinfo.date_time = date_time
zipinfo.compress_type = zipfile.ZIP_DEFLATED zipinfo.compress_type = zipfile.ZIP_DEFLATED
zipinfo.external_attr = 0o644 << 16 zipinfo.external_attr = 0o644 << 16
zfile.writestr(zipinfo, data) zfile.writestr(zipinfo, data)
@ -1196,14 +1138,15 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
except: except:
raise ReportError(_("Could not create %s") % self.filename) raise ReportError(_("Could not create %s") % self.filename)
t = time.localtime(time.time())[:6] now = time.localtime(time.time())[:6]
self._add_zip(zfile, "META-INF/manifest.xml", self.mfile.getvalue(), t) self._add_zip(zfile, "META-INF/manifest.xml", self.mfile.getvalue(),
self._add_zip(zfile, "content.xml", self.cntntx.getvalue(), t) now)
self._add_zip(zfile, "meta.xml", self.meta.getvalue(), t) self._add_zip(zfile, "content.xml", self.cntntx.getvalue(), now)
self._add_zip(zfile, "settings.xml", self.stfile.getvalue(), t) self._add_zip(zfile, "meta.xml", self.meta.getvalue(), now)
self._add_zip(zfile, "styles.xml", self.sfile.getvalue(), t) self._add_zip(zfile, "settings.xml", self.stfile.getvalue(), now)
self._add_zip(zfile, "mimetype", self.mimetype.getvalue(), t) self._add_zip(zfile, "styles.xml", self.sfile.getvalue(), now)
self._add_zip(zfile, "mimetype", self.mimetype.getvalue(), now)
self.mfile.close() self.mfile.close()
self.cntnt.close() self.cntnt.close()
@ -1215,7 +1158,8 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
for image in self.media_list: for image in self.media_list:
try: try:
with open(image[0], mode='rb') as ifile: with open(image[0], mode='rb') as ifile:
self._add_zip(zfile, "Pictures/%s" % image[1], ifile.read(), t) self._add_zip(zfile, "Pictures/%s" % image[1],
ifile.read(), now)
except OSError as msg: except OSError as msg:
errmsg = "%s\n%s" % (_("Could not open %s") % image[0], errmsg = "%s\n%s" % (_("Could not open %s") % image[0],
msg) msg)
@ -1248,8 +1192,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
for style_name in styles.get_paragraph_style_names(): for style_name in styles.get_paragraph_style_names():
style = styles.get_paragraph_style(style_name) style = styles.get_paragraph_style(style_name)
wrtf( wrtf('<style:style style:name="%s" ' % style_name +
'<style:style style:name="%s" ' % style_name +
'style:family="paragraph" ' + 'style:family="paragraph" ' +
'style:parent-style-name="Standard" ' + 'style:parent-style-name="Standard" ' +
'style:class="text">\n' + 'style:class="text">\n' +
@ -1279,18 +1222,15 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
elif align == PARA_ALIGN_RIGHT: elif align == PARA_ALIGN_RIGHT:
wrtf('fo:text-align="end" ') wrtf('fo:text-align="end" ')
elif align == PARA_ALIGN_CENTER: elif align == PARA_ALIGN_CENTER:
wrtf( wrtf('fo:text-align="center" '
'fo:text-align="center" '
'style:justify-single-word="false" ' 'style:justify-single-word="false" '
) )
else: else:
wrtf( wrtf('fo:text-align="justify" '
'fo:text-align="justify" '
'style:justify-single-word="false" ' 'style:justify-single-word="false" '
) )
wrtf( wrtf('fo:text-indent="%.2fcm" ' % style.get_first_indent() +
'fo:text-indent="%.2fcm" ' % style.get_first_indent() +
'style:auto-text-indent="false"/> ' + 'style:auto-text-indent="false"/> ' +
'<style:text-properties ' '<style:text-properties '
) )
@ -1300,9 +1240,8 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
wrtf('fo:color="#%02x%02x%02x" ' % color) wrtf('fo:color="#%02x%02x%02x" ' % color)
wrtf('style:font-name="%s" ' % wrtf('style:font-name="%s" ' %
("Arial" ("Arial" if font.get_type_face() == FONT_SANS_SERIF
if font.get_type_face() == FONT_SANS_SERIF else else "Times New Roman")
"Times New Roman")
) )
wrtf('fo:font-size="%.0fpt" ' % font.get_size()) wrtf('fo:font-size="%.0fpt" ' % font.get_size())
@ -1312,8 +1251,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
wrtf('fo:font-weight="bold" ') wrtf('fo:font-weight="bold" ')
if font.get_underline(): if font.get_underline():
wrtf( wrtf('style:text-underline="single" ' +
'style:text-underline="single" ' +
'style:text-underline-color="font-color" ' + 'style:text-underline-color="font-color" ' +
'fo:text-indent="%.2fcm" ' % style.get_first_indent() + 'fo:text-indent="%.2fcm" ' % style.get_first_indent() +
'fo:margin-right="%.2fcm" ' % style.get_right_margin() + 'fo:margin-right="%.2fcm" ' % style.get_right_margin() +
@ -1321,8 +1259,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
'fo:margin-top="%.2fcm" ' % style.get_top_margin() + 'fo:margin-top="%.2fcm" ' % style.get_top_margin() +
'fo:margin-bottom="%.2fcm"\n' % style.get_bottom_margin() 'fo:margin-bottom="%.2fcm"\n' % style.get_bottom_margin()
) )
wrtf( wrtf('/>\n'
'/>\n'
'</style:style>\n' '</style:style>\n'
) )
@ -1332,7 +1269,9 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
wrtf('<draw:stroke-dash draw:name="gramps_%s" draw:style="rect" ' wrtf('<draw:stroke-dash draw:name="gramps_%s" draw:style="rect" '
'draw:dots1="%d" draw:dots1-length="0.102cm" ' 'draw:dots1="%d" draw:dots1-length="0.102cm" '
'draw:dots2="%d" draw:dots2-length="0.102cm" ' 'draw:dots2="%d" draw:dots2-length="0.102cm" '
'draw:distance="%5.3fcm" />\n' % (line_style, dash_array[0], dash_array[0], dash_array[1] * 0.051)) 'draw:distance="%5.3fcm" />\n' %
(line_style, dash_array[0], dash_array[0],
dash_array[1] * 0.051))
# Current no leading number format for headers # Current no leading number format for headers
@ -1360,8 +1299,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
#wrtf('text:level="10" style:num-format=""/>\n') #wrtf('text:level="10" style:num-format=""/>\n')
#wrtf('</text:outline-style>\n') #wrtf('</text:outline-style>\n')
wrtf( wrtf('<text:notes-configuration '
'<text:notes-configuration '
'text:note-class="footnote" ' 'text:note-class="footnote" '
'style:num-format="1" ' 'style:num-format="1" '
'text:start-value="0" ' 'text:start-value="0" '
@ -1369,15 +1307,13 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
'text:start-numbering-at="document"/> ' 'text:start-numbering-at="document"/> '
) )
wrtf( wrtf('<text:notes-configuration '
'<text:notes-configuration '
'text:note-class="endnote" ' 'text:note-class="endnote" '
'style:num-format="i" ' 'style:num-format="i" '
'text:start-value="0"/> ' 'text:start-value="0"/> '
) )
wrtf( wrtf('<text:linenumbering-configuration '
'<text:linenumbering-configuration '
'text:number-lines="false" ' 'text:number-lines="false" '
'text:offset="0.499cm" ' 'text:offset="0.499cm" '
'style:num-format="1" ' 'style:num-format="1" '
@ -1386,8 +1322,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
) )
wrtf('</office:styles>\n') wrtf('</office:styles>\n')
wrtf( wrtf('<office:automatic-styles>\n' +
'<office:automatic-styles>\n' +
_SHEADER_FOOTER + _SHEADER_FOOTER +
'<style:page-layout style:name="pm1">\n' + '<style:page-layout style:name="pm1">\n' +
'<style:page-layout-properties ' + '<style:page-layout-properties ' +
@ -1399,13 +1334,11 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
) )
wrtf('style:print-orientation="%s" ' % wrtf('style:print-orientation="%s" ' %
("portrait" ("portrait" if self.paper.get_orientation() == PAPER_PORTRAIT
if self.paper.get_orientation() == PAPER_PORTRAIT else else "landscape")
"landscape")
) )
wrtf( wrtf('fo:margin-top="%.2fcm" '
'fo:margin-top="%.2fcm" '
% self.paper.get_top_margin() + % self.paper.get_top_margin() +
'fo:margin-bottom="%.2fcm" ' 'fo:margin-bottom="%.2fcm" '
% self.paper.get_bottom_margin() + % self.paper.get_bottom_margin() +
@ -1424,30 +1357,26 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
) )
# header # header
wrtf( wrtf('<style:header-style>\n'
'<style:header-style>\n'
'<style:header-footer-properties ' '<style:header-footer-properties '
'fo:min-height="0cm" fo:margin-bottom="0.499cm"/>\n' 'fo:min-height="0cm" fo:margin-bottom="0.499cm"/>\n'
'</style:header-style>\n' '</style:header-style>\n'
) )
# footer # footer
wrtf( wrtf('<style:footer-style>\n'
'<style:footer-style>\n'
'<style:header-footer-properties ' '<style:header-footer-properties '
'fo:min-height="0cm" fo:margin-bottom="0.499cm"/>\n' 'fo:min-height="0cm" fo:margin-bottom="0.499cm"/>\n'
'</style:footer-style>\n' '</style:footer-style>\n'
) )
# End of page layout # End of page layout
wrtf( wrtf('</style:page-layout>\n'
'</style:page-layout>\n'
'</office:automatic-styles>\n' '</office:automatic-styles>\n'
) )
# Master Styles # Master Styles
wrtf( wrtf('<office:master-styles>\n'
'<office:master-styles>\n'
'<style:master-page style:name="Standard" ' '<style:master-page style:name="Standard" '
'style:page-layout-name="pm1">\n' 'style:page-layout-name="pm1">\n'
# header # header
@ -1540,7 +1469,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
s_tags = styledtext.get_tags() s_tags = styledtext.get_tags()
markuptext = self._backend.add_markup_from_styled(text, s_tags, '\n') markuptext = self._backend.add_markup_from_styled(text, s_tags, '\n')
if links == True: if links is True:
markuptext = re.sub(URL_PATTERN, _CLICKABLE, markuptext) markuptext = re.sub(URL_PATTERN, _CLICKABLE, markuptext)
# we need to know if we have new styles to add. # we need to know if we have new styles to add.
@ -1551,10 +1480,10 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
# The first element is the StyleType and the second one is the value # The first element is the StyleType and the second one is the value
start = 0 start = 0
while 1: while 1:
m = NewStyle.search(markuptext, start) m = NEW_STYLE.search(markuptext, start)
if not m: if not m:
break break
self.StyleList_notes.append([m.group(1)+m.group(2), self.stylelist_notes.append([m.group(1)+m.group(2),
m.group(1), m.group(1),
m.group(2)]) m.group(2)])
start = m.end() start = m.end()
@ -1567,7 +1496,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.start_paragraph(style_name) self.start_paragraph(style_name)
linenb = 1 linenb = 1
else: else:
if ( linenb > 1 ): if linenb > 1:
self.cntnt.write('<text:line-break/>') self.cntnt.write('<text:line-break/>')
self.cntnt.write(line) self.cntnt.write(line)
linenb += 1 linenb += 1
@ -1576,13 +1505,13 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
def write_text(self, text, mark=None, links=False): def write_text(self, text, mark=None, links=False):
""" """
Uses the xml.sax.saxutils.escape function to convert XML Uses the xml.sax.saxutils.escape function to convert XML
entities. The _esc_map dictionary allows us to add our own entities. The ESC_MAP dictionary allows us to add our own
mappings. mappings.
@param mark: IndexMark to use for indexing @param mark: IndexMark to use for indexing
""" """
text = escape(text, _esc_map) text = escape(text, ESC_MAP)
if links == True: if links is True:
text = re.sub(URL_PATTERN, _CLICKABLE, text) text = re.sub(URL_PATTERN, _CLICKABLE, text)
self._write_mark(mark, text) self._write_mark(mark, text)
@ -1594,7 +1523,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
Insert a mark at this point in the document. Insert a mark at this point in the document.
""" """
if mark: if mark:
key = escape(mark.key, _esc_map) key = escape(mark.key, ESC_MAP)
key = key.replace('"', '&quot;') key = key.replace('"', '&quot;')
if mark.type == INDEX_TYPE_ALP: if mark.type == INDEX_TYPE_ALP:
self.cntnt.write( self.cntnt.write(
@ -1705,7 +1634,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
'xmlns:manifest="urn:oasis:names:tc:opendocument' + 'xmlns:manifest="urn:oasis:names:tc:opendocument' +
':xmlns:manifest:1.0">' + ':xmlns:manifest:1.0">' +
'<manifest:file-entry ' + '<manifest:file-entry ' +
'manifest:media-type="%s" ' % _apptype + 'manifest:media-type="%s" ' % APP_TYPE +
'manifest:full-path="/"/>' 'manifest:full-path="/"/>'
) )
@ -1780,8 +1709,8 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
style_sheet = self.get_style_sheet() style_sheet = self.get_style_sheet()
stype = style_sheet.get_draw_style(style) stype = style_sheet.get_draw_style(style)
pname = stype.get_paragraph_style() pname = stype.get_paragraph_style()
p = style_sheet.get_paragraph_style(pname) para = style_sheet.get_paragraph_style(pname)
font = p.get_font() font = para.get_font()
size = font.get_size() size = font.get_size()
height = size * (len(text)) height = size * (len(text))
@ -1809,7 +1738,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
'<draw:text-box>\n' + '<draw:text-box>\n' +
'<text:p text:style-name="X%s">' % pname + '<text:p text:style-name="X%s">' % pname +
'<text:span text:style-name="F%s">' % pname + '<text:span text:style-name="F%s">' % pname +
escape('\n'.join(text), _esc_map) + escape('\n'.join(text), ESC_MAP) +
'</text:span></text:p>\n</draw:text-box>\n' + '</text:span></text:p>\n</draw:text-box>\n' +
'</draw:frame>\n') '</draw:frame>\n')
@ -1894,7 +1823,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
'<text:p text:style-name="F%s">' % para_name + '<text:p text:style-name="F%s">' % para_name +
'<text:span text:style-name="F%s">' % para_name + '<text:span text:style-name="F%s">' % para_name +
#' fo:max-height="%.2f">' % font.get_size() + #' fo:max-height="%.2f">' % font.get_size() +
escape(text, _esc_map) + escape(text, ESC_MAP) +
'</text:span>' + '</text:span>' +
'</text:p>' + '</text:p>' +
'</draw:text-box>\n' + '</draw:text-box>\n' +
@ -1940,7 +1869,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.cntnt.write( self.cntnt.write(
'<text:p text:style-name="%s">' % para_name + '<text:p text:style-name="%s">' % para_name +
'<text:span text:style-name="F%s">' % para_name + '<text:span text:style-name="F%s">' % para_name +
escape(text, _esc_map) + escape(text, ESC_MAP) +
'</text:span>' '</text:span>'
'</text:p>\n' '</text:p>\n'
) )
@ -1976,7 +1905,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
'<draw:text-box>' + '<draw:text-box>' +
'<text:p text:style-name="X%s">' % para_name + '<text:p text:style-name="X%s">' % para_name +
'<text:span text:style-name="F%s">' % para_name + '<text:span text:style-name="F%s">' % para_name +
escape(text, _esc_map) + escape(text, ESC_MAP) +
'</text:span>\n' + '</text:span>\n' +
'</text:p>\n' + '</text:p>\n' +
'</draw:text-box>' '</draw:text-box>'
@ -1991,27 +1920,29 @@ def process_spaces(line, format):
If the text is flowed (format==0), then leading spaces (after ignoring XML) If the text is flowed (format==0), then leading spaces (after ignoring XML)
are removed. Embedded multiple spaces are reduced to one by ODF are removed. Embedded multiple spaces are reduced to one by ODF
If the text is pre-formatted (format==1). then all spaces (after ignoring XML) If the text is pre-formatted (format==1), then all spaces (after ignoring
are replaced by "<text:s/>" XML) are replaced by "<text:s/>"
Returns the processed text, and the number of significant (i.e. non-white-space) chars. Returns the processed text, and the number of significant
(i.e. non-white-space) chars.
""" """
txt = "" txt = ""
xml = False xml = False
sigcount = 0 sigcount = 0
# we loop through every character, which is very inefficient, but an attempt to use # We loop through every character, which is very inefficient, but an attempt
# a regex replace didn't always work. This was the code that was replaced. # to use a regex replace didn't always work. This was the code that was
# replaced.
# Problem, we may not replace ' ' in xml tags, so we use a regex # Problem, we may not replace ' ' in xml tags, so we use a regex
# self.cntnt.write(re.sub(' (?=([^(<|>)]*<[^>]*>)*[^>]*$)', # self.cntnt.write(re.sub(' (?=([^(<|>)]*<[^>]*>)*[^>]*$)',
# "<text:s/>", line)) # "<text:s/>", line))
for char in line: for char in line:
if char == '<' and xml == False: if char == '<' and xml is False:
xml = True xml = True
txt += char txt += char
elif char == '>' and xml == True: elif char == '>' and xml is True:
xml = False xml = False
txt += char txt += char
elif xml == True: elif xml is True:
txt += char txt += char
elif char == " " or char == "\t": elif char == " " or char == "\t":
if format == 0 and sigcount == 0: if format == 0 and sigcount == 0:

View File

@ -24,24 +24,26 @@
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
# python modules # Python modules
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
import logging import logging
LOG = logging.getLogger(".rtfdoc")
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
# Load the base BaseDoc class # Gramps modules
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
from gramps.gen.plug.docgen import (BaseDoc, TextDoc, FONT_SERIF, PARA_ALIGN_RIGHT, from gramps.gen.plug.docgen import (
PARA_ALIGN_CENTER, PARA_ALIGN_JUSTIFY, BaseDoc, TextDoc, FONT_SERIF, PARA_ALIGN_RIGHT, PARA_ALIGN_CENTER,
URL_PATTERN) PARA_ALIGN_JUSTIFY, URL_PATTERN)
from gramps.gen.utils.image import image_size, image_actual_size, resize_to_jpeg_buffer from gramps.gen.utils.image import (image_size, image_actual_size,
resize_to_jpeg_buffer)
from gramps.gen.errors import ReportError from gramps.gen.errors import ReportError
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
LOG = logging.getLogger(".rtfdoc")
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
@ -52,15 +54,18 @@ _CLICKABLE = r'''{\\field{\\*\\fldinst HYPERLINK "\1"}{\\fldrslt \1}}'''
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
# RTF uses a unit called "twips" for its measurements. According to the # Functions
# RTF specification, 1 point is 20 twips. This routines converts
# centimeters to twips
#
# 2.54 cm/inch 72pts/inch, 20twips/pt
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
def twips(cm): def twips(length_cm):
return int(((cm/2.54)*72)+0.5)*20 """
RTF uses a unit called "twips" for its measurements. According to the
RTF specification, 1 point is 20 twips. This routines converts
centimeters to twips
2.54 cm/inch 72pts/inch, 20twips/pt
"""
return int(((length_cm/2.54)*72)+0.5)*20
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
@ -69,16 +74,12 @@ def twips(cm):
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
class RTFDoc(BaseDoc, TextDoc): class RTFDoc(BaseDoc, TextDoc):
"""
#-------------------------------------------------------------------- Opens the file, and writes the header. Builds the color and font tables.
# Fonts are chosen using the MS TrueType fonts, since it is assumed that if
# Opens the file, and writes the header. Builds the color and font you are generating RTF, you are probably targeting Word. This generator
# tables. Fonts are chosen using the MS TrueType fonts, since it assumes a Western Europe character set.
# is assumed that if you are generating RTF, you are probably """
# targeting Word. This generator assumes a Western Europe character
# set.
#
#--------------------------------------------------------------------
def open(self, filename): def open(self, filename):
if filename[-4:] != ".rtf": if filename[-4:] != ".rtf":
self.filename = filename + ".rtf" self.filename = filename + ".rtf"
@ -86,7 +87,7 @@ class RTFDoc(BaseDoc,TextDoc):
self.filename = filename self.filename = filename
try: try:
self.f = open(self.filename,"w") self.file = open(self.filename, "w")
except IOError as msg: except IOError as msg:
errmsg = "%s\n%s" % (_("Could not create %s") % self.filename, msg) errmsg = "%s\n%s" % (_("Could not create %s") % self.filename, msg)
raise ReportError(errmsg) raise ReportError(errmsg)
@ -95,7 +96,7 @@ class RTFDoc(BaseDoc,TextDoc):
style_sheet = self.get_style_sheet() style_sheet = self.get_style_sheet()
self.f.write( self.file.write(
'{\\rtf1\\ansi\\ansicpg1252\\deff0\n' '{\\rtf1\\ansi\\ansicpg1252\\deff0\n'
'{\\fonttbl\n' '{\\fonttbl\n'
'{\\f0\\froman\\fcharset0\\fprq0 Times New Roman;}\n' '{\\f0\\froman\\fcharset0\\fprq0 Times New Roman;}\n'
@ -106,21 +107,21 @@ class RTFDoc(BaseDoc,TextDoc):
self.color_map = {} self.color_map = {}
index = 1 index = 1
self.color_map[(0, 0, 0)] = 0 self.color_map[(0, 0, 0)] = 0
self.f.write('\\red0\\green0\\blue0;') self.file.write('\\red0\\green0\\blue0;')
for style_name in style_sheet.get_paragraph_style_names(): for style_name in style_sheet.get_paragraph_style_names():
style = style_sheet.get_paragraph_style(style_name) style = style_sheet.get_paragraph_style(style_name)
fgcolor = style.get_font().get_color() fgcolor = style.get_font().get_color()
bgcolor = style.get_background_color() bgcolor = style.get_background_color()
if fgcolor not in self.color_map: if fgcolor not in self.color_map:
self.color_map[fgcolor] = index self.color_map[fgcolor] = index
self.f.write('\\red%d\\green%d\\blue%d;' % fgcolor) self.file.write('\\red%d\\green%d\\blue%d;' % fgcolor)
index += 1 index += 1
if bgcolor not in self.color_map: if bgcolor not in self.color_map:
self.f.write('\\red%d\\green%d\\blue%d;' % bgcolor) self.file.write('\\red%d\\green%d\\blue%d;' % bgcolor)
self.color_map[bgcolor] = index self.color_map[bgcolor] = index
index += 1 index += 1
self.f.write('}\n') self.file.write('}\n')
self.f.write( self.file.write(
'\\kerning0\\cf0\\viewkind1' + '\\kerning0\\cf0\\viewkind1' +
'\\paperw%d' % twips(self.paper.get_size().get_width()) + '\\paperw%d' % twips(self.paper.get_size().get_width()) +
'\\paperh%d' % twips(self.paper.get_size().get_height()) + '\\paperh%d' % twips(self.paper.get_size().get_height()) +
@ -139,8 +140,8 @@ class RTFDoc(BaseDoc,TextDoc):
# #
#-------------------------------------------------------------------- #--------------------------------------------------------------------
def close(self): def close(self):
self.f.write('}\n') self.file.write('}\n')
self.f.close() self.file.close()
#-------------------------------------------------------------------- #--------------------------------------------------------------------
# #
@ -148,7 +149,7 @@ class RTFDoc(BaseDoc,TextDoc):
# #
#-------------------------------------------------------------------- #--------------------------------------------------------------------
def end_page(self): def end_page(self):
self.f.write('\\sbkpage\n') self.file.write('\\sbkpage\n')
#-------------------------------------------------------------------- #--------------------------------------------------------------------
# #
@ -160,67 +161,67 @@ class RTFDoc(BaseDoc,TextDoc):
def start_paragraph(self, style_name, leader=None): def start_paragraph(self, style_name, leader=None):
self.opened = 0 self.opened = 0
style_sheet = self.get_style_sheet() style_sheet = self.get_style_sheet()
p = style_sheet.get_paragraph_style(style_name) para = style_sheet.get_paragraph_style(style_name)
# build font information # build font information
f = p.get_font() font = para.get_font()
size = f.get_size()*2 size = font.get_size()*2
bgindex = self.color_map[p.get_background_color()] bgindex = self.color_map[para.get_background_color()]
fgindex = self.color_map[f.get_color()] fgindex = self.color_map[font.get_color()]
if f.get_type_face() == FONT_SERIF: if font.get_type_face() == FONT_SERIF:
self.font_type = '\\f0' self.font_type = '\\f0'
else: else:
self.font_type = '\\f1' self.font_type = '\\f1'
self.font_type += '\\fs%d\\cf%d\\cb%d' % (size, fgindex, bgindex) self.font_type += '\\fs%d\\cf%d\\cb%d' % (size, fgindex, bgindex)
if f.get_bold(): if font.get_bold():
self.font_type += "\\b" self.font_type += "\\b"
if f.get_underline(): if font.get_underline():
self.font_type += "\\ul" self.font_type += "\\ul"
if f.get_italic(): if font.get_italic():
self.font_type += "\\i" self.font_type += "\\i"
# build paragraph information # build paragraph information
if not self.in_table: if not self.in_table:
self.f.write('\\pard') self.file.write('\\pard')
if p.get_alignment() == PARA_ALIGN_RIGHT: if para.get_alignment() == PARA_ALIGN_RIGHT:
self.f.write('\\qr') self.file.write('\\qr')
elif p.get_alignment() == PARA_ALIGN_CENTER: elif para.get_alignment() == PARA_ALIGN_CENTER:
self.f.write('\\qc') self.file.write('\\qc')
self.f.write( self.file.write(
'\\ri%d' % twips(p.get_right_margin()) + '\\ri%d' % twips(para.get_right_margin()) +
'\\li%d' % twips(p.get_left_margin()) + '\\li%d' % twips(para.get_left_margin()) +
'\\fi%d' % twips(p.get_first_indent()) '\\fi%d' % twips(para.get_first_indent())
) )
if p.get_alignment() == PARA_ALIGN_JUSTIFY: if para.get_alignment() == PARA_ALIGN_JUSTIFY:
self.f.write('\\qj') self.file.write('\\qj')
if p.get_padding(): if para.get_padding():
self.f.write('\\sa%d' % twips(p.get_padding()/2.0)) self.file.write('\\sa%d' % twips(para.get_padding()/2.0))
if p.get_top_border(): if para.get_top_border():
self.f.write('\\brdrt\\brdrs') self.file.write('\\brdrt\\brdrs')
if p.get_bottom_border(): if para.get_bottom_border():
self.f.write('\\brdrb\\brdrs') self.file.write('\\brdrb\\brdrs')
if p.get_left_border(): if para.get_left_border():
self.f.write('\\brdrl\\brdrs') self.file.write('\\brdrl\\brdrs')
if p.get_right_border(): if para.get_right_border():
self.f.write('\\brdrr\\brdrs') self.file.write('\\brdrr\\brdrs')
if p.get_first_indent(): if para.get_first_indent():
self.f.write('\\fi%d' % twips(p.get_first_indent())) self.file.write('\\fi%d' % twips(para.get_first_indent()))
if p.get_left_margin(): if para.get_left_margin():
self.f.write('\\li%d' % twips(p.get_left_margin())) self.file.write('\\li%d' % twips(para.get_left_margin()))
if p.get_right_margin(): if para.get_right_margin():
self.f.write('\\ri%d' % twips(p.get_right_margin())) self.file.write('\\ri%d' % twips(para.get_right_margin()))
if leader: if leader:
self.opened = 1 self.opened = 1
self.f.write('\\tx%d' % twips(p.get_left_margin())) self.file.write('\\tx%d' % twips(para.get_left_margin()))
self.f.write('{%s ' % self.font_type) self.file.write('{%s ' % self.font_type)
self.write_text(leader) self.write_text(leader)
self.f.write(self.text) self.file.write(self.text)
self.text = "" self.text = ""
self.f.write('\\tab}') self.file.write('\\tab}')
self.opened = 0 self.opened = 0
#-------------------------------------------------------------------- #--------------------------------------------------------------------
@ -233,20 +234,21 @@ class RTFDoc(BaseDoc,TextDoc):
#-------------------------------------------------------------------- #--------------------------------------------------------------------
def end_paragraph(self): def end_paragraph(self):
# FIXME: I don't understand why no end paragraph marker is output when # FIXME: I don't understand why no end paragraph marker is output when
# we are inside a table. Since at least version 3.2.2, this seems to mean that # we are inside a table. Since at least version 3.2.2, this seems to
# there is no new paragraph after the first line of a table entry. # mean that there is no new paragraph after the first line of a table
# entry.
# For example in the birth cell, the first paragraph should be the # For example in the birth cell, the first paragraph should be the
# description (21 Jan 1900 in London); if there is a note following this, # description (21 Jan 1900 in London); if there is a note following
# there is no newline between the description and the note. # this, there is no newline between the description and the note.
if not self.in_table: if not self.in_table:
self.f.write(self.text) self.file.write(self.text)
LOG.debug("end_paragraph: opened: %d write: %s" % LOG.debug("end_paragraph: opened: %d write: %s",
(self.opened, self.opened,
self.text + '}' if self.opened else "" + "newline")) self.text + '}' if self.opened else "" + "newline")
if self.opened: if self.opened:
self.f.write('}') self.file.write('}')
self.opened = 0 self.opened = 0
self.f.write('\n\\par') self.file.write('\n\\par')
self.text = "" self.text = ""
else: else:
if self.text == "": if self.text == "":
@ -259,7 +261,7 @@ class RTFDoc(BaseDoc,TextDoc):
# #
#-------------------------------------------------------------------- #--------------------------------------------------------------------
def page_break(self): def page_break(self):
self.f.write('\\page\n') self.file.write('\\page\n')
#-------------------------------------------------------------------- #--------------------------------------------------------------------
# #
@ -267,9 +269,8 @@ class RTFDoc(BaseDoc,TextDoc):
# #
#-------------------------------------------------------------------- #--------------------------------------------------------------------
def start_bold(self): def start_bold(self):
LOG.debug("start_bold: opened: %d saved text: %s" % LOG.debug("start_bold: opened: %d saved text: %s", self.opened,
(self.opened, '}' if self.opened else "" + '{%s\\b ' % self.font_type)
'}' if self.opened else "" + '{%s\\b ' % self.font_type))
if self.opened: if self.opened:
self.text += '}' self.text += '}'
self.text += '{%s\\b ' % self.font_type self.text += '{%s\\b ' % self.font_type
@ -281,9 +282,8 @@ class RTFDoc(BaseDoc,TextDoc):
# #
#-------------------------------------------------------------------- #--------------------------------------------------------------------
def end_bold(self): def end_bold(self):
LOG.debug("end_bold: opened: %d saved text: %s" % LOG.debug("end_bold: opened: %d saved text: %s", self.opened,
(self.opened, self.text + '}')
self.text + '}'))
if not self.opened == 1: if not self.opened == 1:
print(self.opened) print(self.opened)
raise RuntimeError raise RuntimeError
@ -330,7 +330,7 @@ class RTFDoc(BaseDoc,TextDoc):
self.cell = 0 self.cell = 0
self.prev = 0 self.prev = 0
self.cell_percent = 0.0 self.cell_percent = 0.0
self.f.write('\\trowd\n') self.file.write('\\trowd\n')
#-------------------------------------------------------------------- #--------------------------------------------------------------------
# #
@ -339,11 +339,11 @@ class RTFDoc(BaseDoc,TextDoc):
# #
#-------------------------------------------------------------------- #--------------------------------------------------------------------
def end_row(self): def end_row(self):
self.f.write('{') self.file.write('{')
for line in self.contents: for line in self.contents:
self.f.write(line) self.file.write(line)
self.f.write('\\cell ') self.file.write('\\cell ')
self.f.write('}\\pard\\intbl\\row\n') self.file.write('}\\pard\\intbl\\row\n')
#-------------------------------------------------------------------- #--------------------------------------------------------------------
# #
@ -359,18 +359,18 @@ class RTFDoc(BaseDoc,TextDoc):
s = styles.get_cell_style(style_name) s = styles.get_cell_style(style_name)
self.remain = span -1 self.remain = span -1
if s.get_top_border(): if s.get_top_border():
self.f.write('\\clbrdrt\\brdrs\\brdrw10\n') self.file.write('\\clbrdrt\\brdrs\\brdrw10\n')
if s.get_bottom_border(): if s.get_bottom_border():
self.f.write('\\clbrdrb\\brdrs\\brdrw10\n') self.file.write('\\clbrdrb\\brdrs\\brdrw10\n')
if s.get_left_border(): if s.get_left_border():
self.f.write('\\clbrdrl\\brdrs\\brdrw10\n') self.file.write('\\clbrdrl\\brdrs\\brdrw10\n')
if s.get_right_border(): if s.get_right_border():
self.f.write('\\clbrdrr\\brdrs\\brdrw10\n') self.file.write('\\clbrdrr\\brdrs\\brdrw10\n')
table_width = float(self.paper.get_usable_width()) table_width = float(self.paper.get_usable_width())
for cell in range(self.cell, self.cell+span): for cell in range(self.cell, self.cell+span):
self.cell_percent += float(self.tbl_style.get_column_width(cell)) self.cell_percent += float(self.tbl_style.get_column_width(cell))
cell_width = twips((table_width * self.cell_percent)/100.0) cell_width = twips((table_width * self.cell_percent)/100.0)
self.f.write('\\cellx%d\\pard\intbl\n' % cell_width) self.file.write('\\cellx%d\\pard\intbl\n' % cell_width)
self.cell += 1 self.cell += 1
#-------------------------------------------------------------------- #--------------------------------------------------------------------
@ -391,35 +391,37 @@ class RTFDoc(BaseDoc,TextDoc):
# dumped as a string of HEX numbers. # dumped as a string of HEX numbers.
# #
#-------------------------------------------------------------------- #--------------------------------------------------------------------
def add_media(self, name, pos, x_cm, y_cm, alt='', style_name=None, crop=None): def add_media(self, name, pos, x_cm, y_cm, alt='', style_name=None,
crop=None):
nx, ny = image_size(name) width, height = image_size(name)
if (nx, ny) == (0,0): if (width, height) == (0, 0):
return return
(act_width, act_height) = image_actual_size(x_cm, y_cm, nx, ny) (act_width, act_height) = image_actual_size(x_cm, y_cm, width, height)
act_width = twips(act_width) act_width = twips(act_width)
act_height = twips(act_height) act_height = twips(act_height)
size = [act_width, act_height] size = [act_width, act_height]
buf = resize_to_jpeg_buffer(name, size, crop=crop) buf = resize_to_jpeg_buffer(name, size, crop=crop)
act_width = size[0] # In case it changed because of cropping or keeping the ratio # The size may change because of cropping or keeping the ratio
act_width = size[0]
act_height = size[1] act_height = size[1]
self.f.write('{\*\shppict{\\pict\\jpegblip') self.file.write('{\*\shppict{\\pict\\jpegblip')
self.f.write('\\picwgoal%d\\pichgoal%d\n' % (act_width,act_height)) self.file.write('\\picwgoal%d\\pichgoal%d\n' % (act_width, act_height))
index = 1 index = 1
for i in buf: for i in buf:
self.f.write('%02x' % i) self.file.write('%02x' % i)
if index%32 == 0: if index%32 == 0:
self.f.write('\n') self.file.write('\n')
index = index+1 index = index+1
self.f.write('}}\\par\n') self.file.write('}}\\par\n')
if len(alt): if len(alt):
self.f.write('%s\n\\par\n' % '\\par'.join(alt)) self.file.write('%s\n\\par\n' % '\\par'.join(alt))
def write_styled_note(self, styledtext, format, style_name, def write_styled_note(self, styledtext, format, style_name,
contains_html=False, links=False): contains_html=False, links=False):
@ -447,15 +449,15 @@ class RTFDoc(BaseDoc,TextDoc):
self.start_paragraph(style_name) self.start_paragraph(style_name)
linenb = 1 linenb = 1
else: else:
if ( linenb > 1 ): if linenb > 1:
self.write_text('\\line ') self.write_text('\\line ')
self.write_text(line, links=links) self.write_text(line, links=links)
linenb += 1 linenb += 1
# FIXME: I don't understand why these newlines are necessary. # FIXME: I don't understand why these newlines are necessary.
# It may be related to the behaviour of end_paragraph inside tables, and # It may be related to the behaviour of end_paragraph inside tables,
# write_text converting \n to end paragraph. # and write_text converting \n to end paragraph.
# This code prevents the whole document going wrong, but seems to produce an extra # This code prevents the whole document going wrong, but seems to
# paragraph mark at the end of each table cell. # produce an extra paragraph mark at the end of each table cell.
if self.in_table: if self.in_table:
# # Add LF when in table as in indiv_complete report # # Add LF when in table as in indiv_complete report
self.write_text('\n') self.write_text('\n')
@ -472,9 +474,7 @@ class RTFDoc(BaseDoc,TextDoc):
def write_text(self, text, mark=None, links=False): def write_text(self, text, mark=None, links=False):
# Convert to unicode, just in case it's not. Fix of bug 2449. # Convert to unicode, just in case it's not. Fix of bug 2449.
text = str(text) text = str(text)
LOG.debug("write_text: opened: %d input text: %s" % LOG.debug("write_text: opened: %d input text: %s", self.opened, text)
(self.opened,
text))
if self.opened == 0: if self.opened == 0:
self.opened = 1 self.opened = 1
self.text += '{%s ' % self.font_type self.text += '{%s ' % self.font_type
@ -488,18 +488,17 @@ class RTFDoc(BaseDoc,TextDoc):
# RTF req valus in decimal, not hex. # RTF req valus in decimal, not hex.
self.text += '{\\uc1\\u%d\\uc0}' % ord(i) self.text += '{\\uc1\\u%d\\uc0}' % ord(i)
elif i == '\n': elif i == '\n':
self.text += '\n\\par '; self.text += '\n\\par '
elif i == '{' or i == '}' or i == '\\': elif i == '{' or i == '}' or i == '\\':
self.text += '\\%s' % i self.text += '\\%s' % i
else: else:
self.text += i self.text += i
if links == True: if links is True:
import re import re
self.text = re.sub(URL_PATTERN, _CLICKABLE, self.text) self.text = re.sub(URL_PATTERN, _CLICKABLE, self.text)
LOG.debug("write_text, exit: opened: %d saved text: %s" % LOG.debug("write_text, exit: opened: %d saved text: %s", self.opened,
(self.opened, self.text)
self.text))
def process_spaces(line, format): def process_spaces(line, format):
""" """
@ -511,26 +510,27 @@ def process_spaces(line, format):
are removed, and multiple spaces are reduced to one. are removed, and multiple spaces are reduced to one.
If the text is pre-formatted (format==1). then all spaces are preserved If the text is pre-formatted (format==1). then all spaces are preserved
Note that xml is just treated like any other text, Note that xml is just treated like any other text, because it will be from
because it will be from the original note, and it is just printed, not interpreted. the original note, and it is just printed, not interpreted.
Returns the processed text, and the number of significant (i.e. non-white-space) chars. Returns the processed text, and the number of significant
(i.e. non-white-space) chars.
""" """
txt = "" txt = ""
xml = False xml = False
space = False space = False
sigcount = 0 sigcount = 0
# we loop through every character, which is very inefficient, but an attempt to use # we loop through every character, which is very inefficient, but an
# a regex replace didn't always work. # attempt to use a regex replace didn't always work.
for char in line: for char in line:
if char == " " or char == "\t": if char == " " or char == "\t":
if format == 1: if format == 1:
txt += char txt += char
elif format == 0 and sigcount == 0: elif format == 0 and sigcount == 0:
pass pass
elif format == 0 and space == False: elif format == 0 and space is False:
space = True space = True
txt += char txt += char
elif format == 0 and space == True: elif format == 0 and space is True:
pass pass
else: else:
sigcount += 1 sigcount += 1

View File

@ -27,7 +27,7 @@ SVG document generator.
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# python modules # Python modules
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
from io import StringIO from io import StringIO
@ -37,12 +37,12 @@ from io import StringIO
# Gramps modules # Gramps modules
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
from gramps.gen.plug.docgen import BaseDoc, DrawDoc, SOLID, FONT_SANS_SERIF from gramps.gen.plug.docgen import BaseDoc, DrawDoc, SOLID, FONT_SANS_SERIF
from gramps.gen.errors import ReportError from gramps.gen.errors import ReportError
from gramps.gen.plug.menu import EnumeratedListOption from gramps.gen.plug.menu import EnumeratedListOption
from gramps.gen.plug.report import DocOptions from gramps.gen.plug.report import DocOptions
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@ -53,7 +53,7 @@ class SvgDrawDoc(BaseDoc, DrawDoc):
def __init__(self, styles, type, options=None): def __init__(self, styles, type, options=None):
BaseDoc.__init__(self, styles, type) BaseDoc.__init__(self, styles, type)
self.f = None self.file = None
self.filename = None self.filename = None
self.level = 0 self.level = 0
self.time = "0000-00-00T00:00:00" self.time = "0000-00-00T00:00:00"
@ -83,18 +83,18 @@ class SvgDrawDoc(BaseDoc, DrawDoc):
name = "%s.svg" % self.root name = "%s.svg" % self.root
try: try:
self.f = open(name,"w", encoding="utf-8") self.file = open(name, "w", encoding="utf-8")
except IOError as msg: except IOError as msg:
raise ReportError(_("Could not create %s") % name, msg) raise ReportError(_("Could not create %s") % name, msg)
except: except:
raise ReportError(_("Could not create %s") % name) raise ReportError(_("Could not create %s") % name)
self.t = StringIO() self.buffer = StringIO()
width = self.paper.get_size().get_width() width = self.paper.get_size().get_width()
height = self.paper.get_size().get_height() height = self.paper.get_size().get_height()
self.f.write( self.file.write(
'<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n' '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n'
'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" ' '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" '
'"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">\n' '"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">\n'
@ -110,8 +110,8 @@ class SvgDrawDoc(BaseDoc, DrawDoc):
style_sheet = self.get_style_sheet() style_sheet = self.get_style_sheet()
stype = style_sheet.get_draw_style(style) stype = style_sheet.get_draw_style(style)
pname = stype.get_paragraph_style() pname = stype.get_paragraph_style()
p = style_sheet.get_paragraph_style(pname) para = style_sheet.get_paragraph_style(pname)
font = p.get_font() font = para.get_font()
size = font.get_size() size = font.get_size()
width = height = 0 width = height = 0
@ -124,40 +124,40 @@ class SvgDrawDoc(BaseDoc, DrawDoc):
xpos = (centerx - (width/2.0)) xpos = (centerx - (width/2.0))
ypos = (centery - (height/2.0)) ypos = (centery - (height/2.0))
self.t.write( self.buffer.write(
'<text ' + '<text ' +
'x="%4.2f" y="%4.2f" ' % (xpos, ypos) + 'x="%4.2f" y="%4.2f" ' % (xpos, ypos) +
'transform="rotate(%d %4.2f %4.2f)" ' % (angle, centerx, centery) + 'transform="rotate(%d %4.2f %4.2f)" ' % (angle, centerx, centery) +
'style="fill:#%02x%02x%02x; '% font.get_color() 'style="fill:#%02x%02x%02x; '% font.get_color()
) )
if font.get_bold(): if font.get_bold():
self.t.write('font-weight:bold;') self.buffer.write('font-weight:bold;')
if font.get_italic(): if font.get_italic():
self.t.write('font-style:italic;') self.buffer.write('font-style:italic;')
self.t.write('font-size:%dpt; ' % size) self.buffer.write('font-size:%dpt; ' % size)
if font.get_type_face() == FONT_SANS_SERIF: if font.get_type_face() == FONT_SANS_SERIF:
self.t.write('font-family:sans-serif;') self.buffer.write('font-family:sans-serif;')
else: else:
self.t.write('font-family:serif;') self.buffer.write('font-family:serif;')
self.t.write('">') self.buffer.write('">')
for line in text: for line in text:
# Center this line relative to the rest of the text # Center this line relative to the rest of the text
linex = xpos + (width - self.string_width(font, line)) / 2 linex = xpos + (width - self.string_width(font, line)) / 2
self.t.write( self.buffer.write(
'<tspan x="%4.2f" dy="%d">' % (linex, size) + '<tspan x="%4.2f" dy="%d">' % (linex, size) +
line + line +
'</tspan>' '</tspan>'
) )
self.t.write('</text>\n') self.buffer.write('</text>\n')
def end_page(self): def end_page(self):
# Print the text last for each page so that it is rendered on top of # Print the text last for each page so that it is rendered on top of
# other graphic elements. # other graphic elements.
self.f.write(self.t.getvalue()) self.file.write(self.buffer.getvalue())
self.t.close() self.buffer.close()
self.f.write('</svg>\n') self.file.write('</svg>\n')
self.f.close() self.file.close()
def draw_line(self, style, x1, y1, x2, y2): def draw_line(self, style, x1, y1, x2, y2):
x1 += self.paper.get_left_margin() x1 += self.paper.get_left_margin()
@ -166,17 +166,17 @@ class SvgDrawDoc(BaseDoc, DrawDoc):
y2 += self.paper.get_top_margin() y2 += self.paper.get_top_margin()
style_sheet = self.get_style_sheet() style_sheet = self.get_style_sheet()
s = style_sheet.get_draw_style(style) draw_style = style_sheet.get_draw_style(style)
line_out = '<line x1="%4.2fcm" y1="%4.2fcm" ' % (x1, y1) line_out = '<line x1="%4.2fcm" y1="%4.2fcm" ' % (x1, y1)
line_out += 'x2="%4.2fcm" y2="%4.2fcm" ' % (x2, y2) line_out += 'x2="%4.2fcm" y2="%4.2fcm" ' % (x2, y2)
line_out += 'style="stroke:#%02x%02x%02x; ' % s.get_color() line_out += 'style="stroke:#%02x%02x%02x; ' % draw_style.get_color()
if s.get_line_style() != SOLID: if draw_style.get_line_style() != SOLID:
line_out += 'stroke-dasharray: %s; ' % ( line_out += 'stroke-dasharray: %s; ' % (
",".join(map(str, s.get_dash_style())) ",".join(map(str, draw_style.get_dash_style()))
) )
line_out += 'stroke-width:%.2fpt;"/>\n' % s.get_line_width() line_out += 'stroke-width:%.2fpt;"/>\n' % draw_style.get_line_width()
self.f.write(line_out) self.file.write(line_out)
def draw_path(self, style, path): def draw_path(self, style, path):
style_sheet = self.get_style_sheet() style_sheet = self.get_style_sheet()
@ -190,16 +190,17 @@ class SvgDrawDoc(BaseDoc, DrawDoc):
",".join(map(str, stype.get_dash_style())) ",".join(map(str, stype.get_dash_style()))
) )
line_out += ' stroke-width:%.2fpt;"' % stype.get_line_width() line_out += ' stroke-width:%.2fpt;"' % stype.get_line_width()
line_out += ' points="%.2f,%.2f' % units((point[0]+self.paper.get_left_margin(), line_out += ' points="%.2f,%.2f' % units(
(point[0]+self.paper.get_left_margin(),
point[1]+self.paper.get_top_margin())) point[1]+self.paper.get_top_margin()))
self.f.write(line_out) self.file.write(line_out)
for point in path[1:]: for point in path[1:]:
self.f.write( self.file.write(
' %.2f,%.2f' ' %.2f,%.2f'
% units((point[0]+self.paper.get_left_margin(), % units((point[0]+self.paper.get_left_margin(),
point[1]+self.paper.get_top_margin())) point[1]+self.paper.get_top_margin()))
) )
self.f.write('"/>\n') self.file.write('"/>\n')
def draw_box(self, style, text, x, y, w, h, mark=None): def draw_box(self, style, text, x, y, w, h, mark=None):
""" @param mark: IndexMark to use for indexing (not supported) """ """ @param mark: IndexMark to use for indexing (not supported) """
@ -211,7 +212,7 @@ class SvgDrawDoc(BaseDoc, DrawDoc):
shadow_width = box_style.get_shadow_space() shadow_width = box_style.get_shadow_space()
if box_style.get_shadow() and shadow_width > 0: if box_style.get_shadow() and shadow_width > 0:
self.f.write( self.file.write(
'<rect ' + '<rect ' +
'x="%4.2fcm" ' % (x + shadow_width) + 'x="%4.2fcm" ' % (x + shadow_width) +
'y="%4.2fcm" ' % (y + shadow_width) + 'y="%4.2fcm" ' % (y + shadow_width) +
@ -232,37 +233,37 @@ class SvgDrawDoc(BaseDoc, DrawDoc):
",".join(map(str, box_style.get_dash_style())) ",".join(map(str, box_style.get_dash_style()))
) )
line_out += 'stroke-width:%f;"/>\n' % box_style.get_line_width() line_out += 'stroke-width:%f;"/>\n' % box_style.get_line_width()
self.f.write(line_out) self.file.write(line_out)
if text: if text:
para_name = box_style.get_paragraph_style() para_name = box_style.get_paragraph_style()
assert( para_name != '' ) assert para_name != ''
p = style_sheet.get_paragraph_style(para_name) para = style_sheet.get_paragraph_style(para_name)
font = p.get_font() font = para.get_font()
font_size = font.get_size() font_size = font.get_size()
lines = text.split('\n') lines = text.split('\n')
mar = 10/28.35 mar = 10/28.35
fs = (font_size/28.35) * 1.2 fsize = (font_size/28.35) * 1.2
center = y + (h + fs)/2.0 + (fs*0.2) center = y + (h + fsize)/2.0 + (fsize*0.2)
ystart = center - (fs/2.0) * len(lines) ystart = center - (fsize/2.0) * len(lines)
for i, line in enumerate(lines): for i, line in enumerate(lines):
ypos = ystart + (i * fs) ypos = ystart + (i * fsize)
self.t.write( self.buffer.write(
'<text ' + '<text ' +
'x="%4.2fcm" ' % (x+mar) + 'x="%4.2fcm" ' % (x+mar) +
'y="%4.2fcm" ' % ypos + 'y="%4.2fcm" ' % ypos +
'style="fill:#%02x%02x%02x; '% font.get_color() 'style="fill:#%02x%02x%02x; '% font.get_color()
) )
if font.get_bold(): if font.get_bold():
self.t.write(' font-weight:bold;') self.buffer.write(' font-weight:bold;')
if font.get_italic(): if font.get_italic():
self.t.write(' font-style:italic;') self.buffer.write(' font-style:italic;')
self.t.write(' font-size:%dpt;' % font_size) self.buffer.write(' font-size:%dpt;' % font_size)
if font.get_type_face() == FONT_SANS_SERIF: if font.get_type_face() == FONT_SANS_SERIF:
self.t.write(' font-family:sans-serif;') self.buffer.write(' font-family:sans-serif;')
else: else:
self.t.write(' font-family:serif;') self.buffer.write(' font-family:serif;')
self.t.write( self.buffer.write(
'">' + '">' +
line + line +
'</text>\n' '</text>\n'
@ -276,27 +277,27 @@ class SvgDrawDoc(BaseDoc, DrawDoc):
style_sheet = self.get_style_sheet() style_sheet = self.get_style_sheet()
box_style = style_sheet.get_draw_style(style) box_style = style_sheet.get_draw_style(style)
para_name = box_style.get_paragraph_style() para_name = box_style.get_paragraph_style()
p = style_sheet.get_paragraph_style(para_name) para = style_sheet.get_paragraph_style(para_name)
font = p.get_font() font = para.get_font()
font_size = font.get_size() font_size = font.get_size()
fs = (font_size/28.35) * 1.2 fsize = (font_size/28.35) * 1.2
self.t.write( self.buffer.write(
'<text ' + '<text ' +
'x="%4.2fcm" ' % x + 'x="%4.2fcm" ' % x +
'y="%4.2fcm" ' % (y+fs) + 'y="%4.2fcm" ' % (y+fsize) +
'style="fill:#%02x%02x%02x;'% font.get_color() 'style="fill:#%02x%02x%02x;'% font.get_color()
) )
if font.get_bold(): if font.get_bold():
self.t.write('font-weight:bold;') self.buffer.write('font-weight:bold;')
if font.get_italic(): if font.get_italic():
self.t.write('font-style:italic;') self.buffer.write('font-style:italic;')
self.t.write('font-size:%dpt; ' % font_size) self.buffer.write('font-size:%dpt; ' % font_size)
if font.get_type_face() == FONT_SANS_SERIF: if font.get_type_face() == FONT_SANS_SERIF:
self.t.write('font-family:sans-serif;') self.buffer.write('font-family:sans-serif;')
else: else:
self.t.write('font-family:serif;') self.buffer.write('font-family:serif;')
self.t.write( self.buffer.write(
'">' + '">' +
text + text +
'</text>\n' '</text>\n'
@ -307,8 +308,8 @@ class SvgDrawDoc(BaseDoc, DrawDoc):
style_sheet = self.get_style_sheet() style_sheet = self.get_style_sheet()
box_style = style_sheet.get_draw_style(style) box_style = style_sheet.get_draw_style(style)
para_name = box_style.get_paragraph_style() para_name = box_style.get_paragraph_style()
p = style_sheet.get_paragraph_style(para_name) para = style_sheet.get_paragraph_style(para_name)
font = p.get_font() font = para.get_font()
width = self.string_width(font, text) / 72 width = self.string_width(font, text) / 72
x -= width x -= width
self.draw_text(style, text, x, y) self.draw_text(style, text, x, y)