diff --git a/src/plugins/docgen/ODFDoc.py b/src/plugins/docgen/ODFDoc.py
index 0b5e60385..5783394cb 100644
--- a/src/plugins/docgen/ODFDoc.py
+++ b/src/plugins/docgen/ODFDoc.py
@@ -2,7 +2,7 @@
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
-# Copyright (C) 2005-2006 Serge Noiraud
+# Copyright (C) 2005-2009 Serge Noiraud
# Copyright (C) 2007-2009 Brian G. Matherly
#
# This program is free software; you can redistribute it and/or modify
@@ -22,6 +22,38 @@
# $Id$
+"""
+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
@@ -38,7 +70,6 @@ import locale
from cStringIO import StringIO
from math import pi, cos, sin
from xml.sax.saxutils import escape
-import operator
#-------------------------------------------------------------------------
#
@@ -56,7 +87,6 @@ from libodfbackend import OdfBackend
import const
from ReportBase import ReportUtils
import ImgManip
-import Utils
import Errors
#-------------------------------------------------------------------------
@@ -89,13 +119,29 @@ NewStyle = re.compile('style-name="([a-zA-Z0-9]*)__([#a-zA-Z0-9 ]*)__">')
#
#-------------------------------------------------------------------------
class ODFDoc(BaseDoc, TextDoc, DrawDoc):
+ """
+ The ODF document class
+ """
- def __init__(self, styles, type):
- BaseDoc.__init__(self, styles, type)
+ def __init__(self, styles, ftype):
+ """
+ Class init
+ """
+ BaseDoc.__init__(self, styles, ftype)
self.media_list = []
+ self.init_called = False
self.cntnt = None
- self._backend = None
+ self.cntnt1 = None
+ self.cntnt2 = None
+ self.cntntx = None
+ self.sfile = None
+ self.mimetype = None
+ self.meta = None
+ self.mfile = None
self.filename = None
+ self.lang = None
+ self._backend = None
+ self.span = 0
self.level = 0
self.time = "0000-00-00T00:00:00"
self.new_page = 0
@@ -105,6 +151,9 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.StyleList = [] # styles to create depending on styled notes.
def open(self, filename):
+ """
+ Open the new document
+ """
t = time.localtime(time.time())
self.time = "%04d-%02d-%02dT%02d:%02d:%02d" % t[:6]
@@ -120,6 +169,9 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.cntnt2 = StringIO()
def init(self):
+ """
+ Create the document header
+ """
assert (not self.init_called)
self.init_called = True
@@ -134,29 +186,44 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.StyleList = [] # styles to create depending on styled notes.
self.cntnt1.write('\n')
self.cntnt1.write('\n')
self.cntnt1.write('\n')
self.cntnt1.write('\n')
- self.cntnt1.write('\n')
+ self.cntnt1.write('\n')
self.cntnt1.write('\n')
self.cntnt2.write('\n')
self.cntnt2.write('\n')
- self.cntnt2.write('\n')
- self.cntnt2.write('\n')
+ self.cntnt2.write('\n')
self.cntnt2.write('\n')
- self.cntnt2.write('')
- self.cntnt2.write('')
+ self.cntnt2.write('')
+ self.cntnt2.write('')
self.cntnt2.write('\n')
- self.cntnt2.write('')
+ self.cntnt2.write('')
self.cntnt2.write('')
self.cntnt2.write('\n')
@@ -188,7 +260,8 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.cntnt.write('\n')
self.cntnt.write('\n')
- self.cntnt.write('\n')
self.cntnt.write('\n')
self.cntnt.write('\n')
@@ -237,7 +315,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
# Graphic style for items with a clear background
self.cntnt.write('\n')
- self.cntnt.write('\t\n' % style_name)
- self.cntnt.write('\n')
+ self.cntnt.write('\n')
self.cntnt.write('\n')
self.cntnt.write('\n')
@@ -325,7 +408,8 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
if font.get_italic():
self.cntnt.write('fo:font-style="italic" ')
self.cntnt.write('fo:font-size="%.2fpt" ' % font.get_size())
- self.cntnt.write('style:font-size-asian="%.2fpt"/> ' % font.get_size())
+ self.cntnt.write('style:font-size-asian="%.2fpt"/> ' %
+ font.get_size())
self.cntnt.write('\n')
for style_name in styles.get_table_style_names():
@@ -334,12 +418,14 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.cntnt.write('style:family="table-properties">\n')
table_width = float(self.get_usable_width())
table_width_str = "%.2f" % table_width
- self.cntnt.write('\n')
self.cntnt.write('\n')
for col in range(0, style.get_columns()):
self.cntnt.write('')
width = table_width * float(style.get_column_width(col)/100.0)
width_str = "%.4f" % width
@@ -372,10 +458,12 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.cntnt.write('/>\n')
self.cntnt.write('\n')
- self.cntnt.write('\n')
+ self.cntnt.write('\n')
self.cntnt.write('\n')
self.cntnt.write('\n')
- self.cntnt.write('\n')
+ self.cntnt.write('\n')
self.cntnt.write('\n')
self.cntnt.write('\n')
self.cntnt.write('\n')
#Begin photo style
- self.cntnt.write('')
- self.cntnt.write('')
self.cntnt.write('\n')
- self.cntnt.write('')
- self.cntnt.write('')
self.cntnt.write('\n')
- self.cntnt.write(' ')
- self.cntnt.write(' ')
self.cntnt.write('\n')
self.cntnt.write('')
- self.cntnt.write('')
self.cntnt.write('\n')
@@ -451,8 +552,35 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.cntnt.write('form:automatic-focus="false" ')
self.cntnt.write('form:apply-design-mode="false"/>\n')
+ def uniq(self, List, funct=None):
+ """
+ We want no duplicate in the list
+ """
+ # order preserving
+ if funct is None:
+ def funct(x):
+ """
+ function used to compare elements
+ """
+ return x
+ seen = {}
+ result = []
+ for item in List:
+ marker = funct(item[0])
+ if marker in seen:
+ continue
+ seen[marker] = 1
+ result.append(item)
+ return result
+
def finish_cntnt_creation(self):
+ """
+ We have finished the document.
+ So me must integrate the new fonts and styles where they should be.
+ The content.xml file is closed.
+ """
self.cntntx = StringIO()
+ self.StyleList = self.uniq(self.StyleList)
self.add_styled_notes_fonts()
self.add_styled_notes_styles()
self.cntntx.write(self.cntnt1.getvalue())
@@ -463,6 +591,9 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.cntnt.close()
def close(self):
+ """
+ Close the document and create the odt file
+ """
self.cntnt.write('\n')
self.cntnt.write('\n')
self.cntnt.write('\n')
@@ -476,41 +607,62 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
open_file_with_default_application(self.filename)
def add_styled_notes_fonts(self):
+ """
+ Add the new fonts for Styled notes in the font-face-decls section.
+ """
# Need to add new font for styled notes here.
for style in self.StyleList:
- if ( style[0] == "FontFace" ):
- self.cntnt1.write('\n')
def add_styled_notes_styles(self):
+ """
+ Add the new styles for Styled notes in the automatic-styles section.
+ """
# Need to add new style for styled notes here.
for style in self.StyleList:
- if ( style[0] == "FontSize" ):
- self.cntnt2.write('')
- self.cntnt2.write(' ' % style[1])
+ if ( style[1] == "FontSize" ):
+ self.cntnt2.write(' ')
+ self.cntnt2.write('' %
+ style[2])
self.cntnt2.write('\n')
- elif ( style[0] == "FontColor" ):
- self.cntnt2.write('')
- self.cntnt2.write(' ' % style[1])
+ self.cntnt2.write(' ' %
+ style[2])
self.cntnt2.write('\n')
- elif ( style[0] == "FontHighlight" ):
- self.cntnt2.write('')
- self.cntnt2.write(' ' % style[1])
+ elif ( style[1] == "FontHighlight" ):
+ self.cntnt2.write(' ')
+ self.cntnt2.write('' % style[2])
self.cntnt2.write('\n')
- elif ( style[0] == "FontFace" ):
- self.cntnt2.write('')
- self.cntnt2.write(' ')
+ self.cntnt2.write('')
self.cntnt2.write('\n')
def add_media_object(self, file_name, pos, x_cm, y_cm, alt=''):
+ """
+ Add multi-media documents : photos
+ """
# try to open the image. If the open fails, it probably wasn't
# a valid image (could be a PDF, or a non-image)
@@ -561,6 +713,9 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.cntnt.write('\n')
def start_table(self, name, style_name):
+ """
+ open a table
+ """
self.cntnt.write('\n' % style_name)
styles = self.get_style_sheet()
@@ -570,17 +725,30 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.cntnt.write(style_name + '.' + str(chr(ord('A')+col)) +'"/>\n')
def end_table(self):
+ """
+ close a table
+ """
self.cntnt.write('\n')
def start_row(self):
+ """
+ open a row
+ """
self.cntnt.write('\n')
def end_row(self):
+ """
+ close a row
+ """
self.cntnt.write('\n')
def start_cell(self, style_name, span=1):
+ """
+ open a cell
+ """
self.span = span
- self.cntnt.write(' 1:
self.cntnt.write(' table:number-columns-spanned="%s">\n' % span)
@@ -589,24 +757,42 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.new_cell = 1
def end_cell(self):
+ """
+ close a cell
+ """
self.cntnt.write('\n')
#for col in range(1, self.span):
# self.cntnt.write('\n')
self.new_cell = 0
def start_bold(self):
+ """
+ open bold
+ """
self.cntnt.write('')
def end_bold(self):
+ """
+ close bold
+ """
self.cntnt.write('')
def start_superscript(self):
+ """
+ open superscript
+ """
self.cntnt.write('')
def end_superscript(self):
+ """
+ close superscript
+ """
self.cntnt.write('')
def _add_zip(self, zfile, name, data, t):
+ """
+ Add a zip file to an archive
+ """
zipinfo = zipfile.ZipInfo(name.encode('utf-8'))
zipinfo.date_time = t
zipinfo.compress_type = zipfile.ZIP_DEFLATED
@@ -614,8 +800,11 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
zfile.writestr(zipinfo, data)
def _write_zip(self):
+ """
+ Create the odt file. This is a zip file
+ """
try:
- zfile = zipfile.ZipFile(self.filename, "w", zipfile.ZIP_DEFLATED)
+ zfile = zipfile.ZipFile(self.filename, "w", zipfile.ZIP_DEFLATED)
except IOError, msg:
errmsg = "%s\n%s" % (_("Could not create %s") % self.filename, msg)
raise Errors.ReportError(errmsg)
@@ -642,30 +831,48 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self._add_zip(zfile, "Pictures/%s" % image[1], ifile.read(), t)
ifile.close()
except:
- print "Could not open %s" % image[0]
+ errmsg = "%s\n%s" % (_("Could not open %s") % image[0],
+ msg)
+ raise Errors.ReportError(errmsg)
zfile.close()
def _write_styles_file(self):
+ """
+ create the styles.xml file
+ """
self.sfile = StringIO()
self.sfile.write('\n')
self.sfile.write('\n')
self.sfile.write('\n')
self.sfile.write('\n')
self.sfile.write('\n')
- self.sfile.write('\n')
- self.sfile.write('\n')
+ self.sfile.write('\n')
self.sfile.write(' ')
self.sfile.write('\n')
@@ -803,16 +1018,26 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
# Current no leading number format for headers
#self.sfile.write('\n')
- #self.sfile.write('\n')
- #self.sfile.write('\n')
- #self.sfile.write('\n')
- #self.sfile.write('\n')
- #self.sfile.write('\n')
- #self.sfile.write('\n')
- #self.sfile.write('\n')
- #self.sfile.write('\n')
- #self.sfile.write('\n')
- #self.sfile.write('\n')
+ #self.sfile.write('\n')
+ #self.sfile.write('\n')
+ #self.sfile.write('\n')
+ #self.sfile.write('\n')
+ #self.sfile.write('\n')
+ #self.sfile.write('\n')
+ #self.sfile.write('\n')
+ #self.sfile.write('\n')
+ #self.sfile.write('\n')
+ #self.sfile.write('\n')
#self.sfile.write('\n')
self.sfile.write(' ')
self.sfile.write('\n')
self.sfile.write('\n')
- self.sfile.write('')
self.sfile.write('')
self.sfile.write('\n')
- self.sfile.write('')
self.sfile.write('')
self.sfile.write('\n')
self.sfile.write('\n')
- self.sfile.write('\n')
self.sfile.write('')
#self.sfile.write('')
- #self.sfile.write(' TITRE : %s' % self.title) # How to get the document title here ?
+ # How to get the document title here ?
+ #self.sfile.write(' TITRE : %s' % self.title)
#self.sfile.write('')
#self.sfile.write('')
# footer
@@ -900,15 +1135,27 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.sfile.write('\n')
def page_break(self):
+ """
+ prepare a new page
+ """
self.new_page = 1
def start_page(self):
+ """
+ create a new page
+ """
self.cntnt.write('\n')
def end_page(self):
+ """
+ close the page
+ """
self.cntnt.write('\n')
def start_paragraph(self, style_name, leader=None):
+ """
+ open a new paragraph
+ """
style_sheet = self.get_style_sheet()
style = style_sheet.get_paragraph_style(style_name)
self.level = style.get_header_level()
@@ -929,6 +1176,9 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.new_cell = 0
def end_paragraph(self):
+ """
+ close a paragraph
+ """
if self.level == 0:
self.cntnt.write('\n')
else:
@@ -936,6 +1186,9 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.new_cell = 1
def write_note(self, text, format, style_name):
+ """
+ write a note
+ """
if format == 1:
text = escape(text, _esc_map)
# Replace multiple spaces: have to go from the largest number down
@@ -965,7 +1218,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
s_tags = styledtext.get_tags()
markuptext = self._backend.add_markup_from_styled(text, s_tags)
# we need to know if we have new styles to add.
- # if markuptext contains : FontColor, FontFace, FontSize or FontHighlight
+ # if markuptext contains : FontColor, FontFace, FontSize ...
# we must prepare the new styles for the styles.xml file.
# We are looking for the following format :
# style-name="([a-zA-Z0-9]*)__([a-zA-Z0-9 ])">
@@ -975,10 +1228,17 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
m = NewStyle.search(markuptext, start)
if not m:
break
- self.StyleList.append([m.group(1), m.group(2)])
+ self.StyleList.append([m.group(1)+m.group(2),
+ m.group(1),
+ m.group(2)])
start = m.end()
self.cntnt.write('')
- self.cntnt.write(markuptext)
+ linenb = 1
+ for line in markuptext.split('\n'):
+ if ( linenb > 1 ):
+ self.cntnt.write('')
+ self.cntnt.write(line)
+ linenb += 1
self.cntnt.write('')
def write_text(self, text, mark=None):
@@ -1000,11 +1260,15 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.cntnt.write(escape(text, _esc_map))
def _write_manifest(self):
+ """
+ create the manifest.xml file
+ """
self.mfile = StringIO()
self.mfile.write('\n')
self.mfile.write('')
+ self.mfile.write('xmlns:manifest="urn:oasis:names:tc:opendocument')
+ self.mfile.write(':xmlns:manifest:1.0">')
self.mfile.write('')
@@ -1024,19 +1288,27 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.mfile.write('\n')
def _write_mimetype_file(self):
+ """
+ create the mimetype.xml file
+ """
self.mimetype = StringIO()
self.mimetype.write('application/vnd.oasis.opendocument.text')
def _write_meta_file(self):
+ """
+ create the meta.xml file
+ """
self.meta = StringIO()
self.meta.write('\n')
self.meta.write('\n');
+ self.meta.write('xmlns:meta="urn:oasis:names:tc:opendocument')
+ self.meta.write(':xmlns:meta:1.0" ')
+ self.meta.write('office:version="1.0">\n')
self.meta.write('\n')
self.meta.write('')
self.meta.write(const.PROGRAM_NAME + ' ' + const.VERSION)
@@ -1069,7 +1341,9 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.meta.write('%s\n' % self.lang)
self.meta.write('1\n')
self.meta.write('PT0S\n')
- self.meta.write('http://gramps-project.org')
+ self.meta.write('')
+ self.meta.write('http://gramps-project.org')
self.meta.write('\n')
self.meta.write('\n')
self.meta.write('\n')
@@ -1078,6 +1352,9 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.meta.write('\n')
def rotate_text(self, style, text, x, y, angle):
+ """
+ Used to rotate a text with an angle.
+ """
style_sheet = self.get_style_sheet()
stype = style_sheet.get_draw_style(style)
pname = stype.get_paragraph_style()
@@ -1112,6 +1389,9 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.cntnt.write('\n')
def draw_path(self, style, path):
+ """
+ Draw a path
+ """
minx = 9e12
miny = 9e12
maxx = 0
@@ -1123,13 +1403,15 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
maxx = max(point[0], maxx)
maxy = max(point[1], maxy)
- self.cntnt.write('\n')
def draw_line(self, style, x1, y1, x2, y2):
+ """
+ Draw a line
+ """
self.cntnt.write('\n')
def draw_text(self, style, text, x, y):
+ """
+ Draw a text
+ """
style_sheet = self.get_style_sheet()
box_style = style_sheet.get_draw_style(style)
para_name = box_style.get_paragraph_style()
@@ -1182,6 +1470,9 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.cntnt.write('\n')
def draw_box(self, style, text, x, y, w, h):
+ """
+ Draw a box
+ """
style_sheet = self.get_style_sheet()
box_style = style_sheet.get_draw_style(style)
para_name = box_style.get_paragraph_style()
@@ -1215,6 +1506,9 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
self.cntnt.write('\n')
def center_text(self, style, text, x, y):
+ """
+ Center a text in a cell, a row, a line, ...
+ """
style_sheet = self.get_style_sheet()
box_style = style_sheet.get_draw_style(style)
para_name = box_style.get_paragraph_style()