Part 1 basedoc changes: move out backend stuff from BaseDoc, use backend in

the docs. As a dir change will be done, backend itself will be committed 
later, trunk will be broken till then


svn: r12590
This commit is contained in:
Benny Malengier
2009-05-29 19:52:57 +00:00
parent e4b2162bd1
commit f999ba9cc4
4 changed files with 95 additions and 416 deletions

View File

@ -1405,41 +1405,13 @@ class BaseDoc(object):
# TextDoc # TextDoc
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
def noescape(text):
return text
class TextDoc(object): class TextDoc(object):
""" """
Abstract Interface for text document generators. Output formats for Abstract Interface for text document generators. Output formats for
text reports must implment this interface to be used by the report text reports must implment this interface to be used by the report
system. system.
""" """
BOLD = 0
ITALIC = 1
UNDERLINE = 2
FONTFACE = 3
FONTSIZE = 4
FONTCOLOR = 5
HIGHLIGHT = 6
SUPERSCRIPT = 7
SUPPORTED_MARKUP = []
ESCAPE_FUNC = lambda x: noescape
#Map between styletypes and internally used values. This map is needed
# to make TextDoc officially independant of gen.lib.styledtexttag
STYLETYPE_MAP = {
}
CLASSMAP = None
#STYLETAGTABLE to store markup for write_markup associated with style tags
STYLETAG_MARKUP = {
BOLD : ("", ""),
ITALIC : ("", ""),
UNDERLINE : ("", ""),
SUPERSCRIPT : ("", ""),
}
def page_break(self): def page_break(self):
"Forces a page break, creating a new page" "Forces a page break, creating a new page"
raise NotImplementedError raise NotImplementedError
@ -1592,159 +1564,6 @@ class TextDoc(object):
@param h_cm: height in centimeters @param h_cm: height in centimeters
""" """
raise NotImplementedError raise NotImplementedError
def find_tag_by_stag(self, s_tag):
"""
@param s_tag: object: assumed styledtexttag
@param s_tagvalue: None/int/str: value associated with the tag
A styled tag is type with a value.
Every styled tag must be converted to the tags used in the corresponding
markup for the backend, eg <b>text</b> for bold in html.
These markups are stored in STYLETAG_MARKUP. They are tuples for begin
and end tag
If a markup is not present yet, it is created, using the
_create_xmltag method you can overwrite
"""
type = s_tag.name
if not self.STYLETYPE_MAP or \
self.CLASSMAP <> type.__class__.__name__ :
self.CLASSMAP == type.__class__.__name__
self.STYLETYPE_MAP[type.__class__.BOLD] = self.BOLD
self.STYLETYPE_MAP[type.ITALIC] = self.ITALIC
self.STYLETYPE_MAP[type.UNDERLINE] = self.UNDERLINE
self.STYLETYPE_MAP[type.FONTFACE] = self.FONTFACE
self.STYLETYPE_MAP[type.FONTSIZE] = self.FONTSIZE
self.STYLETYPE_MAP[type.FONTCOLOR] = self.FONTCOLOR
self.STYLETYPE_MAP[type.HIGHLIGHT] = self.HIGHLIGHT
self.STYLETYPE_MAP[type.SUPERSCRIPT] = self.SUPERSCRIPT
typeval = int(s_tag.name)
s_tagvalue = s_tag.value
tag_name = None
if type.STYLE_TYPE[typeval] == bool:
return self.STYLETAG_MARKUP[self.STYLETYPE_MAP[typeval]]
elif type.STYLE_TYPE[typeval] == str:
tag_name = "%d %s" % (typeval, s_tagvalue)
elif type.STYLE_TYPE[typeval] == int:
tag_name = "%d %d" % (typeval, s_tagvalue)
if not tag_name:
return None
tags = self.STYLETAG_MARKUP.get(tag_name)
if tags is not None:
return tags
#no tag known yet, create the markup, add to lookup, and return
tags = self._create_xmltag(self.STYLETYPE_MAP[typeval], s_tagvalue)
self.STYLETAG_MARKUP[tag_name] = tags
return tags
def _create_xmltag(self, type, value):
"""
Create the xmltags for the backend.
Overwrite this method to create functionality with a backend
"""
if type not in self.SUPPORTED_MARKUP:
return None
return ('', '')
def _add_markup_from_styled(self, text, s_tags, split=''):
"""
Input is plain text, output is text with markup added according to the
s_tags which are assumed to be styledtexttags.
When split is given the text will be split over the value given, and
tags applied in such a way that it the text can be safely splitted in
pieces along split
@param text : str, a piece of text
@param s_tags : styledtexttags that must be applied to the text
@param split : str, optional. A string along which the output can
be safely split without breaking the styling.
As adding markup means original text must be escaped, ESCAPE_FUNC is
used
This can be used to convert the text of a styledtext to the format
needed for a document backend
Do not call this method in a report, use the write_markup method
@note: the algorithm is complex as it assumes mixing of tags is not
allowed: eg <b>text<i> here</b> not</i> is assumed invalid
as markup. If the s_tags require such a setup, what is returned
is <b>text</b><i><b> here</b> not</i>
overwrite this method if this complexity is not needed.
"""
FIRST = 0
LAST = 1
tagspos = {}
for s_tag in s_tags:
tag = self.find_tag_by_stag(s_tag)
if tag is not None:
for (start, end) in s_tag.ranges:
if start in tagspos:
tagspos[start] += [(tag, FIRST)]
else:
tagspos[start] = [(tag, FIRST)]
if end in tagspos:
tagspos[end] += [(tag, LAST)]
else:
tagspos[end] = [(tag, LAST)]
start = 0
end = len(text)
keylist = tagspos.keys()
keylist.sort()
keylist = [x for x in keylist if x<=len(text)]
opentags = []
otext = u"" #the output, text with markup
lensplit = len(split)
for pos in keylist:
#write text up to tag
if pos > start:
if split:
#make sure text can split
splitpos = text[start:pos].find(split)
while splitpos <> -1:
otext += self.ESCAPE_FUNC()(text[start:start+splitpos])
#close open tags
for opentag in reversed(opentags):
otext += opentag[1]
#add split text
otext += self.ESCAPE_FUNC()(split)
#open the tags again
for opentag in opentags:
otext += opentag[0]
#obtain new values
start = start + splitpos + lensplit
splitpos = text[start:pos].find(split)
otext += self.ESCAPE_FUNC()(text[start:pos])
#write out tags
for tag in tagspos[pos]:
#close open tags starting from last open
for opentag in reversed(opentags):
otext += opentag[1]
#if start, add to opentag in beginning as first to open
if tag[1] == FIRST:
opentags = [tag[0]] + opentags
else:
#end tag, is closed already, remove from opentag
opentags = [x for x in opentags if not x == tag[0] ]
#now all tags are closed, open the ones that should open
for opentag in opentags:
otext += opentag[0]
start = pos
#add remainder of text, no markup present there
otext += self.ESCAPE_FUNC()(text[start:end])
#opentags should be empty. If not, user gave tags on positions that
# are over the end of the text. Just close the tags still open
if opentags:
print 'WARNING: TextDoc : More style tags in text than length '\
'of text allows.\n', opentags
for opentag in reversed(opentags):
otext += opentag[1]
return otext
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #

View File

@ -40,6 +40,7 @@ from gettext import gettext as _
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
import BaseDoc import BaseDoc
from docbackend.latexbackend import LateXBackend, latexescape
from gen.plug import PluginManager, DocGenPlugin from gen.plug import PluginManager, DocGenPlugin
import ImgManip import ImgManip
import Errors import Errors
@ -128,81 +129,18 @@ class TexFont(object):
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
def latexescape(text):
"""
change text in text that latex shows correctly
special characters: \& \$ \% \# \_ \{ \}
"""
text = text.replace('&','\\&')
text = text.replace('$','\\$')
text = text.replace('%','\\%')
text = text.replace('#','\\#')
text = text.replace('_','\\_')
text = text.replace('{','\\{')
text = text.replace('}','\\}')
return text
def latexescapeverbatim(text):
"""
change text in text that latex shows correctly respecting whitespace
special characters: \& \$ \% \# \_ \{ \}
Now also make sure space and newline is respected
"""
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')
#spaces at begin are normally ignored, make sure they are not.
#due to above a space at begin is now \newline\n\
text = text.replace('\\newline\n\\ ', '\\newline\n\\hspace*{0.1cm}\\ ')
return text
class LaTeXDoc(BaseDoc.BaseDoc,BaseDoc.TextDoc): class LaTeXDoc(BaseDoc.BaseDoc,BaseDoc.TextDoc):
"""LaTeX document interface class. Derived from BaseDoc""" """LaTeX document interface class. Derived from BaseDoc"""
# overwrite base class attributes, they become static var of LaTeXDoc
SUPPORTED_MARKUP = [
BaseDoc.TextDoc.BOLD,
BaseDoc.TextDoc.ITALIC,
BaseDoc.TextDoc.UNDERLINE,
BaseDoc.TextDoc.FONTSIZE,
BaseDoc.TextDoc.FONTFACE,
BaseDoc.TextDoc.SUPERSCRIPT ]
STYLETAG_MARKUP = {
BaseDoc.TextDoc.BOLD : ("\\textbf{", "}"),
BaseDoc.TextDoc.ITALIC : ("\\textit{", "}"),
BaseDoc.TextDoc.UNDERLINE : ("\\underline{", "}"),
BaseDoc.TextDoc.SUPERSCRIPT : ("\\textsuperscript{", "}"),
}
ESCAPE_FUNC = lambda x: latexescape
def page_break(self): def page_break(self):
"Forces a page break, creating a new page" "Forces a page break, creating a new page"
self.f.write('\\newpage ') self._backend.write('\\newpage ')
def open(self,filename): def open(self, filename):
"""Opens the specified file, making sure that it has the """Opens the specified file, making sure that it has the
extension of .tex""" extension of .tex"""
self._backend = LateXBackend(filename)
if filename[-4:] != ".tex": self._backend.open()
self.filename = filename + ".tex"
else:
self.filename = filename
try:
self.f = open(self.filename,"w")
except IOError,msg:
errmsg = "%s\n%s" % (_("Could not create %s") % self.filename, msg)
raise Errors.ReportError(errmsg)
except:
raise Errors.ReportError(_("Could not create %s") % self.filename)
# Font size control seems to be limited. For now, ignore # Font size control seems to be limited. For now, ignore
# any style constraints, and use 12pt has the default # any style constraints, and use 12pt has the default
@ -229,45 +167,45 @@ class LaTeXDoc(BaseDoc.BaseDoc,BaseDoc.TextDoc):
# Use the article template, T1 font encodings, and specify # Use the article template, T1 font encodings, and specify
# that we should use Latin1 and unicode character encodings. # that we should use Latin1 and unicode character encodings.
self.f.write('\\documentclass[%s]{article}\n' % options) self._backend.write('\\documentclass[%s]{article}\n' % options)
self.f.write('\\usepackage[T1]{fontenc}\n') self._backend.write('\\usepackage[T1]{fontenc}\n')
self.f.write('%\n% We use latin1 encoding at a minimum by default.\n') self._backend.write('%\n% We use latin1 encoding at a minimum by default.\n')
self.f.write('% GRAMPS uses unicode UTF-8 encoding for its\n') self._backend.write('% GRAMPS uses unicode UTF-8 encoding for its\n')
self.f.write('% international support. LaTeX can deal gracefully\n') self._backend.write('% international support. LaTeX can deal gracefully\n')
self.f.write('% with unicode encoding by using the ucs style invoked\n') self._backend.write('% with unicode encoding by using the ucs style invoked\n')
self.f.write('% when utf8 is specified as an option to the inputenc\n') self._backend.write('% when utf8 is specified as an option to the inputenc\n')
self.f.write('% package. This package is included by default in some\n') self._backend.write('% package. This package is included by default in some\n')
self.f.write('% installations, but not in others, so we do not make it\n') self._backend.write('% installations, but not in others, so we do not make it\n')
self.f.write('% the default. Uncomment the second line if you wish to use it\n') self._backend.write('% the default. Uncomment the second line if you wish to use it\n')
self.f.write('% (If you do not have ucs.sty, you may obtain it from\n') self._backend.write('% (If you do not have ucs.sty, you may obtain it from\n')
self.f.write('% http://www.tug.org/tex-archive/macros/latex/contrib/supported/unicode/)\n') self._backend.write('% http://www.tug.org/tex-archive/macros/latex/contrib/supported/unicode/)\n')
self.f.write('%\n') self._backend.write('%\n')
self.f.write('\\usepackage[latin1]{inputenc}\n') self._backend.write('\\usepackage[latin1]{inputenc}\n')
self.f.write('%\\usepackage[latin1,utf8]{inputenc}\n') self._backend.write('%\\usepackage[latin1,utf8]{inputenc}\n')
# add packages (should be standard on a default installation) # add packages (should be standard on a default installation)
# for finer output control. Put comments in file for user to read # for finer output control. Put comments in file for user to read
self.f.write('\\usepackage{graphicx} % Extended graphics support\n') self._backend.write('\\usepackage{graphicx} % Extended graphics support\n')
self.f.write('\\usepackage{longtable} % For multi-page tables\n') self._backend.write('\\usepackage{longtable} % For multi-page tables\n')
self.f.write('\\usepackage{calc} % For margin indents\n') self._backend.write('\\usepackage{calc} % For margin indents\n')
self.f.write('%\n% Depending on your LaTeX installation, the') self._backend.write('%\n% Depending on your LaTeX installation, the')
self.f.write(' margins may be too\n% narrow. ') self._backend.write(' margins may be too\n% narrow. ')
self.f.write(' This can be corrected by uncommenting the following\n') self._backend.write(' This can be corrected by uncommenting the following\n')
self.f.write('% two lines and adjusting the width appropriately.') self._backend.write('% two lines and adjusting the width appropriately.')
self.f.write(' The example\n% removes 0.5in from each margin.') self._backend.write(' The example\n% removes 0.5in from each margin.')
self.f.write(' (Adds 1 inch to the text)\n') self._backend.write(' (Adds 1 inch to the text)\n')
self.f.write('%\\addtolength{\\oddsidemargin}{-0.5in}\n') self._backend.write('%\\addtolength{\\oddsidemargin}{-0.5in}\n')
self.f.write('%\\addtolength{\\textwidth}{1.0in}\n%\n') self._backend.write('%\\addtolength{\\textwidth}{1.0in}\n%\n')
self.f.write('% Create a margin-adjusting command that allows LaTeX\n') self._backend.write('% Create a margin-adjusting command that allows LaTeX\n')
self.f.write('% to behave like the other gramps-supported output formats\n') self._backend.write('% to behave like the other gramps-supported output formats\n')
self.f.write('\\newlength{\\leftedge}\n') self._backend.write('\\newlength{\\leftedge}\n')
self.f.write('\\setlength{\\leftedge}{\\parindent}\n') self._backend.write('\\setlength{\\leftedge}{\\parindent}\n')
self.f.write('\\newlength{\\grampstext}\n') self._backend.write('\\newlength{\\grampstext}\n')
self.f.write('\\setlength{\\grampstext}{\\textwidth}\n') self._backend.write('\\setlength{\\grampstext}{\\textwidth}\n')
self.f.write('\\newcommand{\\grampsindent}[1]{%\n') self._backend.write('\\newcommand{\\grampsindent}[1]{%\n')
self.f.write(' \\setlength{\\parindent}{\\leftedge + #1}%\n') self._backend.write(' \\setlength{\\parindent}{\\leftedge + #1}%\n')
self.f.write(' \\setlength{\\textwidth}{\\grampstext - #1}%\n') self._backend.write(' \\setlength{\\textwidth}{\\grampstext - #1}%\n')
self.f.write('}\n\n') self._backend.write('}\n\n')
self.f.write('\\begin{document}\n\n') self._backend.write('\\begin{document}\n\n')
self.in_list = 0 self.in_list = 0
self.in_table = 0 self.in_table = 0
@ -351,15 +289,15 @@ class LaTeXDoc(BaseDoc.BaseDoc,BaseDoc.TextDoc):
def close(self): def close(self):
"""Clean up and close the document""" """Clean up and close the document"""
if self.in_list: if self.in_list:
self.f.write('\\end{enumerate}\n') self._backend.write('\\end{enumerate}\n')
self.f.write('\n\\end{document}\n') self._backend.write('\n\\end{document}\n')
self.f.close() self._backend.close()
if self.open_req: if self.open_req:
Utils.open_file_with_default_application(self.filename) Utils.open_file_with_default_application(self._backend.filename)
def end_page(self): def end_page(self):
"""Issue a new page command""" """Issue a new page command"""
self.f.write('\\newpage') self._backend.write('\\newpage')
def start_paragraph(self,style_name,leader=None): def start_paragraph(self,style_name,leader=None):
"""Paragraphs handling - A Gramps paragraph is any """Paragraphs handling - A Gramps paragraph is any
@ -378,11 +316,11 @@ class LaTeXDoc(BaseDoc.BaseDoc,BaseDoc.TextDoc):
if self.indent is not None and not self.in_table: if self.indent is not None and not self.in_table:
myspace = '%scm' % str(self.indent) myspace = '%scm' % str(self.indent)
self.f.write('\\grampsindent{%s}\n' % myspace) self._backend.write('\\grampsindent{%s}\n' % myspace)
self.fix_indent = 1 self.fix_indent = 1
if leader is not None and not self.in_list: if leader is not None and not self.in_list:
self.f.write('\\begin{enumerate}\n') self._backend.write('\\begin{enumerate}\n')
self.in_list = 1 self.in_list = 1
if leader is not None: if leader is not None:
# try obtaining integer # try obtaining integer
@ -394,22 +332,22 @@ class LaTeXDoc(BaseDoc.BaseDoc,BaseDoc.TextDoc):
num = int(leader_1) num = int(leader_1)
except ValueError: except ValueError:
num = 1 num = 1
self.f.write(' \\renewcommand\\theenumi{\\arabic{enumi}}') self._backend.write(' \\renewcommand\\theenumi{\\arabic{enumi}}')
else: else:
# roman, set the case correctly # roman, set the case correctly
if leader_1.islower(): if leader_1.islower():
self.f.write(' \\renewcommand\\theenumi{\\roman{enumi}}') self._backend.write(' \\renewcommand\\theenumi{\\roman{enumi}}')
else: else:
self.f.write(' \\renewcommand\\theenumi{\\Roman{enumi}}') self._backend.write(' \\renewcommand\\theenumi{\\Roman{enumi}}')
self.f.write(' \\setcounter{enumi}{%d} ' % num) self._backend.write(' \\setcounter{enumi}{%d} ' % num)
self.f.write(' \\addtocounter{enumi}{-1}\n') self._backend.write(' \\addtocounter{enumi}{-1}\n')
self.f.write(' \\item ') self._backend.write(' \\item ')
if leader is None and not self.in_list and not self.in_table: if leader is None and not self.in_list and not self.in_table:
self.f.write('\n') self._backend.write('\n')
self.f.write('%s ' % self.fbeg) self._backend.write('%s ' % self.fbeg)
def end_paragraph(self): def end_paragraph(self):
"""End the current paragraph""" """End the current paragraph"""
@ -417,30 +355,30 @@ class LaTeXDoc(BaseDoc.BaseDoc,BaseDoc.TextDoc):
if self.in_list: if self.in_list:
self.in_list = 0 self.in_list = 0
self.f.write('\n\\end{enumerate}\n') self._backend.write('\n\\end{enumerate}\n')
newline = '' newline = ''
elif self.in_table: elif self.in_table:
newline = ('') newline = ('')
self.f.write('%s%s' % (self.fend, newline)) self._backend.write('%s%s' % (self.fend, newline))
if self.fix_indent == 1: if self.fix_indent == 1:
self.fix_indent = 0 self.fix_indent = 0
self.f.write('\\grampsindent{0cm}\n') self._backend.write('\\grampsindent{0cm}\n')
def start_bold(self): def start_bold(self):
"""Bold face""" """Bold face"""
self.f.write('\\textbf{') self._backend.write('\\textbf{')
def end_bold(self): def end_bold(self):
"""End bold face""" """End bold face"""
self.f.write('}') self._backend.write('}')
def start_superscript(self): def start_superscript(self):
self.f.write('\\textsuperscript{') self._backend.write('\\textsuperscript{')
def end_superscript(self): def end_superscript(self):
self.f.write('}') self._backend.write('}')
def start_table(self, name,style_name): def start_table(self, name,style_name):
"""Begin new table""" """Begin new table"""
@ -453,13 +391,13 @@ class LaTeXDoc(BaseDoc.BaseDoc,BaseDoc.TextDoc):
self.numcols = self.tblstyle.get_columns() self.numcols = self.tblstyle.get_columns()
tblfmt = '*{%d}{l}' % self.numcols tblfmt = '*{%d}{l}' % self.numcols
self.f.write('\n\n\\begin{longtable}[l]{%s}\n' % tblfmt) self._backend.write('\n\n\\begin{longtable}[l]{%s}\n' % tblfmt)
def end_table(self): def end_table(self):
"""Close the table environment""" """Close the table environment"""
self.in_table = 0 self.in_table = 0
# Create a paragraph separation below the table. # Create a paragraph separation below the table.
self.f.write('\\end{longtable}\n\\par\n') self._backend.write('\\end{longtable}\n\\par\n')
def start_row(self): def start_row(self):
"""Begin a new row""" """Begin a new row"""
@ -471,14 +409,14 @@ class LaTeXDoc(BaseDoc.BaseDoc,BaseDoc.TextDoc):
def end_row(self): def end_row(self):
"""End the row (new line)""" """End the row (new line)"""
self.f.write('\\\\ ') self._backend.write('\\\\ ')
if self.doline == 1: if self.doline == 1:
if self.skipfirst == 1: if self.skipfirst == 1:
self.f.write('\\cline{2-%d}\n' % self.numcols) self._backend.write('\\cline{2-%d}\n' % self.numcols)
else: else:
self.f.write('\\hline \\\\ \n') self._backend.write('\\hline \\\\ \n')
else: else:
self.f.write('\n') self._backend.write('\n')
def start_cell(self,style_name,span=1): def start_cell(self,style_name,span=1):
"""Add an entry to the table. """Add an entry to the table.
@ -513,14 +451,14 @@ class LaTeXDoc(BaseDoc.BaseDoc,BaseDoc.TextDoc):
self.skipfirst = 1 self.skipfirst = 1
if self.tborder != 0: if self.tborder != 0:
self.f.write('\\hline\n') self._backend.write('\\hline\n')
self.f.write ('\\multicolumn{%d}{%s}{' % (span,cellfmt)) self._backend.write ('\\multicolumn{%d}{%s}{' % (span,cellfmt))
def end_cell(self): def end_cell(self):
"""Prepares for next cell""" """Prepares for next cell"""
self.f.write('} ') self._backend.write('} ')
if self.curcol < self.numcols: if self.curcol < self.numcols:
self.f.write('& ') self._backend.write('& ')
def add_media_object(self, name,pos,x,y): def add_media_object(self, name,pos,x,y):
"""Add photo to report""" """Add photo to report"""
@ -538,11 +476,11 @@ class LaTeXDoc(BaseDoc.BaseDoc,BaseDoc.TextDoc):
# x and y will be maximum width OR height in units of cm # x and y will be maximum width OR height in units of cm
mysize = 'width=%dcm, height=%dcm,keepaspectratio' % (x,y) mysize = 'width=%dcm, height=%dcm,keepaspectratio' % (x,y)
if pos == "right": if pos == "right":
self.f.write('\\hfill\\includegraphics[%s]{%s}\n' % (mysize,picf)) self._backend.write('\\hfill\\includegraphics[%s]{%s}\n' % (mysize,picf))
elif pos == "left": elif pos == "left":
self.f.write('\\includegraphics[%s]{%s}\\hfill\n' % (mysize,picf)) self._backend.write('\\includegraphics[%s]{%s}\\hfill\n' % (mysize,picf))
else: else:
self.f.write('\\centerline{\\includegraphics[%s]{%s}}\n' % (mysize,picf)) self._backend.write('\\centerline{\\includegraphics[%s]{%s}}\n' % (mysize,picf))
def write_text(self,text,mark=None): def write_text(self,text,mark=None):
"""Write the text to the file""" """Write the text to the file"""
@ -552,7 +490,7 @@ class LaTeXDoc(BaseDoc.BaseDoc,BaseDoc.TextDoc):
#hard coded replace of the underline used for missing names/data #hard coded replace of the underline used for missing names/data
text = text.replace('\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_', text = text.replace('\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_\\_',
'\\underline{\hspace{3cm}}') '\\underline{\hspace{3cm}}')
self.f.write(text) self._backend.write(text)
def write_styled_note(self, styledtext, format, style_name): def write_styled_note(self, styledtext, format, style_name):
""" """
@ -569,72 +507,34 @@ class LaTeXDoc(BaseDoc.BaseDoc,BaseDoc.TextDoc):
s_tags = styledtext.get_tags() s_tags = styledtext.get_tags()
if format == 1: if format == 1:
#preformatted, use different escape function #preformatted, use different escape function
BaseDoc.TextDoc.ESCAPE_FUNC = lambda x: latexescapeverbatim self._backend.setescape(True)
markuptext = self._add_markup_from_styled(text, s_tags) markuptext = self._backend.add_markup_from_styled(text, s_tags)
#there is a problem if we write out a note in a table. No newline is #there is a problem if we write out a note in a table. No newline is
# possible, the note runs over the margin into infinity. # possible, the note runs over the margin into infinity.
# A good solution for this ??? # A good solution for this ???
# A quick solution: create a minipage for the note and add that always # A quick solution: create a minipage for the note and add that always
# hoping that the user will have left sufficient room for the page # hoping that the user will have left sufficient room for the page
self.f.write("\\begin{minipage}{{0.8\\linewidth}}\n") self._backend.write("\\begin{minipage}{{0.8\\linewidth}}\n")
self.start_paragraph(style_name) self.start_paragraph(style_name)
self.f.write(markuptext) self._backend.write(markuptext)
self.end_paragraph() self.end_paragraph()
#end the minipage, add trick to have a white line at bottom of note, #end the minipage, add trick to have a white line at bottom of note,
# we assume here a note should be distinct from its surrounding. # we assume here a note should be distinct from its surrounding.
self.f.write("\n\\vspace*{0.5cm} \n\end{minipage}\n") self._backend.write("\n\\vspace*{0.5cm} \n\end{minipage}\n\n")
if format == 1: if format == 1:
#preformatted finished, go back to normal escape function #preformatted finished, go back to normal escape function
BaseDoc.TextDoc.ESCAPE_FUNC = lambda x: latexescape self._backend.setescape(False)
def _create_xmltag(self, type, value):
"""
overwrites the method in BaseDoc.TextDoc.
creates the latex tags needed for non bool style types we support:
BaseDoc.TextDoc.FONTSIZE : use different \large denomination based
on size
: very basic, in mono in the font face
then we use {\ttfamily }
"""
if type not in self.SUPPORTED_MARKUP:
return None
elif type == BaseDoc.TextDoc.FONTSIZE:
#translate size in point to something LaTeX can work with
if value >= 22:
return ("{\\Huge ", "}")
elif value >= 20:
return ("{\\huge ", "}")
elif value >= 18:
return ("{\\LARGE ", "}")
elif value >= 16:
return ("{\\Large ", "}")
elif value >= 14:
return ("{\\large ", "}")
elif value < 8:
return ("{\\scriptsize ", "}")
elif value < 10:
return ("{\\footnotesize ", "}")
elif value < 12:
return ("{\\small ", "}")
else:
return ("", "")
elif type == BaseDoc.TextDoc.FONTFACE:
if 'MONO' in value.upper():
return ("{\\ttfamily ", "}")
elif 'ROMAN' in value.upper():
return ("{\\rmfamily ", "}")
return None
def write_note(self,text,format,style_name): def write_note(self,text,format,style_name):
"""Write the note's text to the file, respecting the format""" """Write the note's text to the file, respecting the format"""
self.start_paragraph(style_name) self.start_paragraph(style_name)
if format == 1: if format == 1:
self.f.write('\\begin{verbatim}') self._backend.write('\\begin{verbatim}')
self.write_text(text) self.write_text(text)
if format == 1: if format == 1:
self.f.write('\\end{verbatim}') self._backend.write('\\end{verbatim}')
self.end_paragraph() self.end_paragraph()
#------------------------------------------------------------------------ #------------------------------------------------------------------------

View File

@ -86,7 +86,7 @@ class PdfDoc(libcairodoc.CairoDoc):
top_margin = self.paper.get_top_margin() * DPI / 2.54 top_margin = self.paper.get_top_margin() * DPI / 2.54
# create cairo context and pango layout # create cairo context and pango layout
surface = cairo.PDFSurface(self._filename, paper_width, paper_height) surface = cairo.PDFSurface(self._backend.filename, paper_width, paper_height)
surface.set_fallback_resolution(300, 300) surface.set_fallback_resolution(300, 300)
cr = pangocairo.CairoContext(cairo.Context(surface)) cr = pangocairo.CairoContext(cairo.Context(surface))
@ -125,7 +125,7 @@ class PdfDoc(libcairodoc.CairoDoc):
# load the result into an external viewer # load the result into an external viewer
if self.open_req: if self.open_req:
Utils.open_file_with_default_application(self._filename) Utils.open_file_with_default_application(self._backend.filename)
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #

View File

@ -32,7 +32,6 @@
#------------------------------------------------------------------------ #------------------------------------------------------------------------
from gettext import gettext as _ from gettext import gettext as _
from math import radians from math import radians
from xml.sax.saxutils import escape
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
@ -43,6 +42,7 @@ import BaseDoc
from ReportBase import ReportUtils from ReportBase import ReportUtils
from Errors import PluginError from Errors import PluginError
from gen.plug import PluginManager, Plugin from gen.plug import PluginManager, Plugin
from docbackend import CairoBackend
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
@ -1200,37 +1200,11 @@ class CairoDoc(BaseDoc.BaseDoc, BaseDoc.TextDoc, BaseDoc.DrawDoc):
page style. page style.
""" """
STYLETAG_TO_PROPERTY = {
BaseDoc.TextDoc.FONTCOLOR : 'foreground',
BaseDoc.TextDoc.HIGHLIGHT : 'background',
BaseDoc.TextDoc.FONTFACE : 'face',
BaseDoc.TextDoc.FONTSIZE : 'size',
}
# overwrite base class attributes, they become static var of CairoDoc
SUPPORTED_MARKUP = [
BaseDoc.TextDoc.BOLD,
BaseDoc.TextDoc.ITALIC,
BaseDoc.TextDoc.UNDERLINE,
BaseDoc.TextDoc.FONTFACE,
BaseDoc.TextDoc.FONTSIZE,
BaseDoc.TextDoc.FONTCOLOR,
BaseDoc.TextDoc.HIGHLIGHT,
BaseDoc.TextDoc.SUPERSCRIPT ]
STYLETAG_MARKUP = {
BaseDoc.TextDoc.BOLD : ("<b>", "</b>"),
BaseDoc.TextDoc.ITALIC : ("<i>", "</i>"),
BaseDoc.TextDoc.UNDERLINE : ("<u>", "</u>"),
BaseDoc.TextDoc.SUPERSCRIPT : ("<sup>", "</sup>"),
}
ESCAPE_FUNC = lambda x: escape
# BaseDoc implementation # BaseDoc implementation
def open(self, filename): def open(self, filename):
self._filename = filename self._backend = CairoBackend(filename)
self._doc = GtkDocDocument() self._doc = GtkDocDocument()
self._active_element = self._doc self._active_element = self._doc
self._pages = [] self._pages = []
@ -1303,21 +1277,6 @@ class CairoDoc(BaseDoc.BaseDoc, BaseDoc.TextDoc, BaseDoc.DrawDoc):
def end_cell(self): def end_cell(self):
self._active_element = self._active_element.get_parent() self._active_element = self._active_element.get_parent()
def _create_xmltag(self, type, value):
"""
overwrites the method in BaseDoc.TextDoc.
creates the pango xml tags needed for non bool style types
"""
if type not in self.SUPPORTED_MARKUP:
return None
if type == BaseDoc.TextDoc.FONTSIZE:
#size is in thousandths of a point in pango
value = str(1000 * value)
return ('<span %s="%s">' % (self.STYLETAG_TO_PROPERTY[type],
self.ESCAPE_FUNC()(value)),
'</span>')
def write_note(self, text, format, style_name): def write_note(self, text, format, style_name):
""" """
Method to write the note objects text on a Method to write the note objects text on a
@ -1358,7 +1317,8 @@ class CairoDoc(BaseDoc.BaseDoc, BaseDoc.TextDoc, BaseDoc.DrawDoc):
s_tags = styledtext.get_tags() s_tags = styledtext.get_tags()
#FIXME: following split should be regex to match \n\s*\n instead? #FIXME: following split should be regex to match \n\s*\n instead?
markuptext = self._add_markup_from_styled(text, s_tags, split='\n\n') markuptext = self._backend.add_markup_from_styled(text, s_tags,
split='\n\n')
if format == 1: if format == 1:
#preformatted, retain whitespace. Cairo retains \n automatically, #preformatted, retain whitespace. Cairo retains \n automatically,
@ -1391,7 +1351,7 @@ class CairoDoc(BaseDoc.BaseDoc, BaseDoc.TextDoc, BaseDoc.DrawDoc):
# calls. This way we save the markup created by the report # calls. This way we save the markup created by the report
# The markup in the note editor is not in the text so is not # The markup in the note editor is not in the text so is not
# considered. It must be added by pango too # considered. It must be added by pango too
text = escape(text) text = self._backend.ESCAPE_FUNC()(text)
self._active_element.add_text(text) self._active_element.add_text(text)
def write_text(self, text, mark=None): def write_text(self, text, mark=None):
@ -1411,7 +1371,7 @@ class CairoDoc(BaseDoc.BaseDoc, BaseDoc.TextDoc, BaseDoc.DrawDoc):
@param s_tags: assumed to be list of styledtexttags to apply to the @param s_tags: assumed to be list of styledtexttags to apply to the
text text
""" """
markuptext = self._add_markup_from_styled(text, s_tags) markuptext = self._backend.add_markup_from_styled(text, s_tags)
self.__write_text(text, markup=True) self.__write_text(text, markup=True)
def add_media_object(self, name, pos, x_cm, y_cm): def add_media_object(self, name, pos, x_cm, y_cm):