diff --git a/gramps2/src/BaseDoc.py b/gramps2/src/BaseDoc.py new file mode 100644 index 000000000..9ce7ca0e5 --- /dev/null +++ b/gramps2/src/BaseDoc.py @@ -0,0 +1,1360 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2000-2003 Donald N. Allingham +# +# Modified September 2002 by Gary Shao +# +# Added line_break() method to TextDoc class to allow breaking a line +# in a paragraph (in those document generators that support it). +# +# Added start_listing() and end_listing() methods to TextDoc class to +# allow displaying text blocks without automatic filling and justification. +# Creating a new listing element seems called for because many document +# generator implementation have to use a different mechanism for text +# that is not going to be automatically filled and justified than that +# used for normal paragraphs. Examples are
 tags in HTML, using
+#   the Verbatim environment in LaTeX, and using the Preformatted class
+#   in reportlab for generating PDF.
+#
+#   Added another option, FONT_MONOSPACE, for use as a font face. This
+#   calls for a fixed-width font (e.g. Courier). It is intended primarily
+#   for supporting the display of text where alignment by character position
+#   may be important, such as in code source or column-aligned data.
+#   Especially useful in styles for the new listing element discussed above.
+#
+#   Added start_italic() and end_italic() methods to TextDoc class to
+#   complement the emphasis of text in a paragraph by bolding with the
+#   ability to italicize segments of text in a paragraph.
+#
+#   Added the show_link() method to TextDoc to enable the creation of
+#   hyperlinks in HTML output. Only produces active links in HTML, while
+#   link will be represented as text in other generator output. (active
+#   links are technically possible in PDF documents, but the reportlab
+#   modules the PDF generator is based on does not support them at this
+#   time)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+"""
+Provides base interface to text based documents. Specific document
+interfaces should be derived from the core classes.
+"""
+
+__author__ = "Donald N. Allingham"
+__version__ = "Revision:$"
+
+#-------------------------------------------------------------------------
+#
+# standard python modules
+#
+#-------------------------------------------------------------------------
+import os
+#import Utils
+
+#-------------------------------------------------------------------------
+#
+# SAX interface
+#
+#-------------------------------------------------------------------------
+try:
+    from xml.sax import make_parser,handler,SAXParseException
+except:
+    from _xmlplus.sax import make_parser,handler,SAXParseException
+
+#-------------------------------------------------------------------------
+#
+# constants
+#
+#-------------------------------------------------------------------------
+FONT_SANS_SERIF = 0
+FONT_SERIF = 1
+FONT_MONOSPACE = 2
+
+#
+# Page orientation
+#
+PAPER_PORTRAIT  = 0
+PAPER_LANDSCAPE = 1
+
+#
+# Paragraph alignment
+#
+PARA_ALIGN_CENTER = 0
+PARA_ALIGN_LEFT   = 1 
+PARA_ALIGN_RIGHT  = 2
+PARA_ALIGN_JUSTIFY= 3
+
+#
+# Text vs. Graphics mode
+#
+TEXT_MODE = 0
+GRAPHICS_MODE = 1
+
+#
+# Line style
+#
+SOLID = 0
+DASHED = 1
+
+
+#------------------------------------------------------------------------
+#
+# cnv2color
+#
+#------------------------------------------------------------------------
+def cnv2color(text):
+    """
+    converts a hex value in the form of #XXXXXX into a tuple of integers
+    representing the RGB values
+    """
+    c0 = int(text[1:3],16)
+    c1 = int(text[3:5],16)
+    c2 = int(text[5:7],16)
+    return (c0,c1,c2)
+
+#------------------------------------------------------------------------
+#
+# PaperStyle
+#
+#------------------------------------------------------------------------
+class PaperStyle:
+    """
+    Defines the dimensions of a sheet of paper. All dimensions are in
+    centimeters.
+    """
+    def __init__(self,name,height,width):
+        """
+        Creates a new paper style with.
+
+        name - Name of the new style
+        height - page height in centimeters
+        width - page width in centimeters
+        """
+        self.name = name
+        self.orientation = PAPER_PORTRAIT
+        self.height = height
+        self.width = width
+
+    def get_name(self):
+        "Returns the name of the paper style"
+        return self.name
+
+    def get_orientation(self):
+        "Returns the page orientation (PAPER_PORTRAIT or PAPER_LANDSCAPE)"
+        return self.orientation
+
+    def set_orientation(self,val):
+        """
+        Sets the page orientation.
+
+        val - new orientation, should be either PAPER_PORTRAIT or
+              PAPER_LANDSCAPE
+        """
+        self.orientation = val
+
+    def get_height(self):
+        "Returns the page height in cm"
+        return self.height
+
+    def set_height(self,height):
+        "Sets the page height in cm"
+        self.height = height
+
+    def get_width(self):
+        "Returns the page width in cm"
+        return self.width
+
+    def set_width(self,width):
+        "Sets the page width in cm"
+        self.width = width
+
+    def get_height_inches(self):
+        "Returns the page height in inches"
+        return self.height / 2.54
+
+    def get_width_inches(self):
+        "Returns the page width in inches"
+        return self.width / 2.54
+
+#------------------------------------------------------------------------
+#
+# FontStyle
+#
+#------------------------------------------------------------------------
+class FontStyle:
+    """
+    Defines a font style. Controls the font face, size, color, and
+    attributes. In order to remain generic, the only font faces available
+    are FONT_SERIF and FONT_SANS_SERIF. Document formatters should convert
+    these to the appropriate fonts for the target format.
+
+    The FontStyle represents the desired characteristics. There are no
+    guarentees that the document format generator will be able implement
+    all or any of the characteristics.
+    """
+    
+    def __init__(self, style=None):
+        """
+        Creates a new FontStyle object, accepting the default values.
+
+        style - if specified, initializes the FontStyle from the passed
+                FontStyle instead of using the defaults.
+        """
+        if style:
+            self.face   = style.face
+            self.size   = style.size
+            self.italic = style.italic
+            self.bold   = style.bold
+            self.color  = style.color
+            self.under  = style.under
+        else:
+            self.face   = FONT_SERIF
+            self.size   = 12
+            self.italic = 0
+            self.bold   = 0
+            self.color  = (0,0,0)
+            self.under  = 0
+            
+    def set(self,face=None,size=None,italic=None,bold=None,underline=None,color=None):
+        """
+        Sets font characteristics.
+
+        face - font type face, either FONT_SERIF or FONT_SANS_SERIF
+        size - type face size in points
+        italic - 1 enables italics, 0 disables italics
+        bold - 1 enables bold face, 0 disables bold face
+        underline - 1 enables underline, 0 disables underline
+        color - an RGB color representation in the form of three integers
+                in the range of 0-255 represeting the red, green, and blue
+                components of a color.
+        """
+        if face != None:
+            self.set_type_face(face)
+        if size != None:
+            self.set_size(size)
+        if italic != None:
+            self.set_italic(italic)
+        if bold != None:
+            self.set_bold(bold)
+        if underline != None:
+            self.set_underline(underline)
+        if color != None:
+            self.set_color(color)
+
+    def set_italic(self,val):
+        "0 disables italics, 1 enables italics"
+        self.italic = val
+
+    def get_italic(self):
+        "1 indicates use italics"
+        return self.italic
+
+    def set_bold(self,val):
+        "0 disables bold face, 1 enables bold face"
+        self.bold = val
+
+    def get_bold(self):
+        "1 indicates use bold face"
+        return self.bold
+
+    def set_color(self,val):
+        "sets the color using an RGB color tuple"
+        self.color = val
+
+    def get_color(self):
+        "Returns an RGB color tuple"
+	return self.color
+
+    def set_size(self,val):
+        "sets font size in points"
+        self.size = val
+
+    def get_size(self):
+        "returns font size in points"
+        return self.size
+
+    def set_type_face(self,val):
+        "sets the font face type"
+        self.face = val
+
+    def get_type_face(self):
+        "returns the font face type"
+        return self.face
+
+    def set_underline(self,val):
+        "1 enables underlining"
+        self.under = val
+
+    def get_underline(self):
+        "1 indicates underlining"
+        return self.under
+
+#------------------------------------------------------------------------
+#
+# TableStyle
+#
+#------------------------------------------------------------------------
+class TableStyle:
+    """
+    Specifies the style or format of a table. The TableStyle contains the
+    characteristics of table width (in percentage of the full width), the
+    number of columns, and the width of each column as a percentage of the
+    width of the table.
+    """
+    def __init__(self,obj=None):
+        """
+        Creates a new TableStyle object, with the values initialized to
+        empty, with allocating space for up to 100 columns.
+
+        obj - if not None, then the object created gets is attributes from
+              the passed object instead of being initialized to empty.
+        """
+        if obj:
+            self.width = obj.width
+            self.columns = obj.columns
+            self.colwid  = obj.colwid[:]
+        else:
+            self.width = 0
+            self.columns = 0
+            self.colwid = [ 0 ] * 100
+
+    def set_width(self,width):
+        """Sets the width of the table in terms of percent of the available
+           width"""
+        self.width = width
+
+    def get_width(self):
+        "Returns the specified width as a percentage of the available space"
+        return self.width
+
+    def set_columns(self,columns):
+        """Sets the number of columns.
+
+           columns - number of columns that should be used.
+        """
+        self.columns = columns
+
+    def get_columns(self):
+        "Returns the number of columns"
+        return self.columns 
+
+    def set_column_widths(self, list):
+        """Sets the width of all the columns at once, taking the percentages
+           from the passed list.
+        """
+        self.columns = len(list)
+        for i in range(self.columns):
+            self.colwid[i] = list[i]
+
+    def set_column_width(self,index,width):
+        """Sets the width of a specified column to the specified width.
+
+           index - column being set (index starts at 0)
+           width - percentage of the table width assigned to the column
+        """
+	self.colwid[index] = width
+
+    def get_column_width(self,index):
+        """
+        Returns the column width of the specified column as a percentage of
+        the entire table width.
+
+        index - column to return (index starts at 0)
+        """
+	return self.colwid[index]
+
+#------------------------------------------------------------------------
+#
+# TableCellStyle
+#
+#------------------------------------------------------------------------
+class TableCellStyle:
+    """
+    Defines the style of a particular table cell. Characteristics are:
+    right border, left border, top border, bottom border, and padding.
+    """
+    def __init__(self,obj=None):
+        """
+        Creates a new TableCellStyle instance.
+
+        obj - if not None, specifies that the values should be copied from
+              the passed object instead of being initialized to empty.
+        """
+        if obj:
+            self.rborder = obj.rborder
+            self.lborder = obj.lborder
+            self.tborder = obj.tborder
+            self.bborder = obj.bborder
+            self.padding = obj.padding
+	    self.longlist = obj.longlist
+        else:
+            self.rborder = 0
+            self.lborder = 0
+            self.tborder = 0
+            self.bborder = 0
+            self.padding = 0
+	    self.longlist = 0
+	    
+    def set_padding(self,val):
+        "Returns the cell padding in centimeters"
+        self.padding = val
+
+    def set_right_border(self,val):
+        """
+        Defines if a right border in used
+
+        val - if 1, a right border is used, if 0, it is not
+        """
+        self.rborder = val
+
+    def set_left_border(self,val):
+        """
+        Defines if a left border in used
+
+        val - if 1, a left border is used, if 0, it is not
+        """
+        self.lborder = val
+
+    def set_top_border(self,val):
+        """
+        Defines if a top border in used
+
+        val - if 1, a top border is used, if 0, it is not
+        """
+        self.tborder = val
+
+    def set_bottom_border(self,val):
+        """
+        Defines if a bottom border in used
+
+        val - if 1, a bottom border is used, if 0, it is not
+        """
+        self.bborder = val
+
+    def set_longlist(self,val):
+        self.longlist = val
+
+    def get_padding(self):
+        "Returns the cell padding in centimeters"
+        return self.padding
+
+    def get_right_border(self):
+        "Returns 1 if a right border is requested"
+        return self.rborder
+
+    def get_left_border(self):
+        "Returns 1 if a left border is requested"
+        return self.lborder
+
+    def get_top_border(self):
+        "Returns 1 if a top border is requested"
+        return self.tborder
+
+    def get_bottom_border(self):
+        "Returns 1 if a bottom border is requested"
+        return self.bborder
+
+    def get_longlist(self):
+        return self.longlist
+
+#------------------------------------------------------------------------
+#
+# ParagraphStyle
+#
+#------------------------------------------------------------------------
+class ParagraphStyle:
+    """
+    Defines the characteristics of a paragraph. The characteristics are:
+    font (a FontStyle instance), right margin, left margin, first indent,
+    alignment, level, top border, bottom border, right border, left
+    border, padding, and background color.
+
+    source - if not None, then the ParagraphStyle is created using the
+             values of the source instead of the default values.
+    """
+    def __init__(self,source=None):
+        if source:
+            self.font    = FontStyle(source.font)
+            self.rmargin = source.rmargin
+            self.lmargin = source.lmargin
+            self.first_indent = source.first_indent
+            self.align   = source.align
+	    self.level   = source.level
+	    self.top_border = source.top_border
+	    self.bottom_border = source.bottom_border
+	    self.right_border = source.right_border
+	    self.left_border = source.left_border
+            self.pad = source.pad
+            self.bgcolor = source.bgcolor
+            self.description = source.description
+        else:
+            self.font    = FontStyle()
+            self.rmargin = 0
+            self.lmargin = 0
+            self.first_indent = 0
+            self.align   = PARA_ALIGN_LEFT
+	    self.level   = 0
+	    self.top_border = 0
+	    self.bottom_border = 0
+	    self.right_border = 0
+	    self.left_border = 0
+            self.pad = 0
+            self.bgcolor = (255,255,255)
+            self.description = ""
+
+    def set_description(self,text):
+        self.description = text
+
+    def get_description(self):
+        return self.description
+
+    def set(self,rmargin=None,lmargin=None,first_indent=None,align=None,
+            tborder=None,bborder=None,rborder=None,lborder=None,pad=None,
+            bgcolor=None,font=None):
+        """
+        Allows the values of the object to be set.
+
+        rmargin - right margin in centimeters
+        lmargin - left margin in centimeters
+        first_indent - first line indent in centimeters
+        align - alignment type (PARA_ALIGN_LEFT, PARA_ALIGN_RIGHT,
+                PARA_ALIGN_CENTER, or PARA_ALIGN_JUSTIFY)
+        tborder - non zero indicates that a top border should be used
+        bborder - non zero indicates that a bottom border should be used
+        rborder - non zero indicates that a right border should be used
+        lborder - non zero indicates that a left border should be used
+        pad - padding in centimeters
+        bgcolor - background color of the paragraph as an RGB tuple.
+        font - FontStyle instance that defines the font
+        """
+        if font != None:
+            self.font = FontStyle(font)
+        if pad != None:
+            self.set_padding(pad)
+        if tborder != None:
+            self.set_top_border(tborder)
+        if bborder != None:
+            self.set_bottom_border(bborder)
+        if rborder != None:
+            self.set_right_border(rborder)
+        if lborder != None:
+            self.set_left_border(lborder)
+        if bgcolor != None:
+            self.set_background_color(bgcolor)
+        if align != None:
+            self.set_alignment(align)
+        if rmargin != None:
+            self.set_right_margin(rmargin)
+        if lmargin != None:
+            self.set_left_margin(lmargin)
+        if first_indent != None:
+            self.set_first_indent(first_indent)
+            
+    def set_header_level(self,level):
+        """
+        Sets the header level for the paragraph. This is useful for
+        numbered paragraphs. A value of 1 indicates a header level
+        format of X, a value of two implies X.X, etc. A value of zero
+        means no header level.
+        """
+        self.level = level
+
+    def get_header_level(self):
+        "Returns the header level of the paragraph"
+        return self.level
+
+    def set_font(self,font):
+        """
+        Sets the font style of the paragraph.
+
+        font - FontStyle object containing the font definition to use.
+        """
+        self.font = FontStyle(font)
+
+    def get_font(self):
+        "Returns the FontStyle of the paragraph"
+        return self.font
+
+    def set_padding(self,val):
+        """
+        Sets the paragraph padding in centimeters
+
+        val - floating point value indicating the padding in centimeters
+        """
+        self.pad = val
+
+    def get_padding(self):
+        """Returns a the padding of the paragraph"""
+        return self.pad
+
+    def set_top_border(self,val):
+        """
+        Sets the presence or absence of top border.
+
+        val - 1 indicates a border should be used, 0 indicates no border.
+        """
+        self.top_border = val
+
+    def get_top_border(self):
+        "Returns 1 if a top border is specified"
+        return self.top_border
+
+    def set_bottom_border(self,val):
+        """
+        Sets the presence or absence of bottom border.
+
+        val - 1 indicates a border should be used, 0 indicates no border.
+        """
+        self.bottom_border = val
+
+    def get_bottom_border(self):
+        "Returns 1 if a bottom border is specified"
+	return self.bottom_border
+
+    def set_left_border(self,val):
+        """
+        Sets the presence or absence of left border.
+
+        val - 1 indicates a border should be used, 0 indicates no border.
+        """
+        self.left_border = val
+
+    def get_left_border(self):
+        "Returns 1 if a left border is specified"
+        return self.left_border
+
+    def set_right_border(self,val):
+        """
+        Sets the presence or absence of rigth border.
+
+        val - 1 indicates a border should be used, 0 indicates no border.
+        """
+        self.right_border = val
+
+    def get_right_border(self):
+        "Returns 1 if a right border is specified"
+        return self.right_border
+
+    def get_background_color(self):
+        """
+        Returns a tuple indicating the RGB components of the background
+        color
+        """
+        return self.bgcolor
+
+    def set_background_color(self,color):
+        """
+        Sets the background color of the paragraph.
+
+        color - tuple representing the RGB components of a color (0,0,0)
+                to (255,255,255)
+        """
+        self.bgcolor = color
+
+    def set_alignment(self,align):
+        """
+        Sets the paragraph alignment.
+
+        align - PARA_ALIGN_LEFT, PARA_ALIGN_RIGHT, PARA_ALIGN_CENTER, or
+                PARA_ALIGN_JUSTIFY
+        """
+        self.align = align
+
+    def get_alignment(self):
+        "Returns the alignment of the paragraph"
+        return self.align
+
+    def get_alignment_text(self):
+        """
+        Returns a text string representing the alginment, either 'left',
+        'right', 'center', or 'justify'
+        """
+        if self.align == PARA_ALIGN_LEFT:
+            return "left"
+        elif self.align == PARA_ALIGN_CENTER:
+            return "center"
+        elif self.align == PARA_ALIGN_RIGHT:
+            return "right"
+        elif self.align == PARA_ALIGN_JUSTIFY:
+            return "justify"
+        return "unknown"
+
+    def set_left_margin(self,value):
+	"sets the left paragraph margin in centimeters"
+        self.lmargin = value
+
+    def set_right_margin(self,value):
+	"sets the right paragraph margin in centimeters"
+        self.rmargin = value
+
+    def set_first_indent(self,value):
+	"sets the first indent margin in centimeters"
+        self.first_indent = value
+
+    def get_left_margin(self):
+	"returns the left margin in centimeters"
+        return self.lmargin
+
+    def get_right_margin(self):
+	"returns the right margin in centimeters"
+        return self.rmargin
+
+    def get_first_indent(self):
+	"returns the first indent margin in centimeters"
+        return self.first_indent
+
+#------------------------------------------------------------------------
+#
+# StyleSheetList
+#
+#------------------------------------------------------------------------
+class StyleSheetList:
+    """
+    Interface into the user's defined style sheets. Each StyleSheetList
+    has a predefined default style specified by the report. Additional
+    styles are loaded from a specified XML file if it exists.
+    """
+    
+    def __init__(self,file,defstyle):
+        """
+        Creates a new StyleSheetList from the specified default style and
+        any other styles that may be defined in the specified file.
+
+        file - XML file that contains style definitions
+        defstyle - default style
+        """
+        defstyle.set_name('default')
+        self.map = { "default" : defstyle }
+        self.file = os.path.expanduser("~/.gramps/" + file)
+        self.parse()
+
+    def delete_style_sheet(self,name):
+        """
+        Removes a style from the list. Since each style must have a
+        unique name, the name is used to delete the stylesheet.
+
+        name - Name of the style to delete
+        """
+        del self.map[name]
+
+    def get_style_sheet_map(self):
+        """
+        Returns the map of names to styles.
+        """
+        return self.map
+
+    def get_style_sheet(self,name):
+        """
+        Returns the StyleSheet associated with the name
+
+        name - name associated with the desired StyleSheet.
+        """
+        return self.map[name]
+
+    def get_style_names(self):
+        "Returns a list of all the style names in the StyleSheetList"
+        return self.map.keys()
+
+    def set_style_sheet(self,name,style):
+        """
+        Adds or replaces a StyleSheet in the StyleSheetList. The
+        default style may not be replaced.
+
+        name - name assocated with the StyleSheet to add or replace.
+        style - definition of the StyleSheet
+        """
+        style.set_name(name)
+        if name != "default":
+            self.map[name] = style
+
+    def save(self):
+        """
+        Saves the current StyleSheet definitions to the associated file.
+        """
+        f = open(self.file,"w")
+        f.write("\n")
+        f.write('\n')
+        for name in self.map.keys():
+            if name == "default":
+                continue
+            sheet = self.map[name]
+            f.write('\n' % name)
+            for p_name in sheet.get_names():
+                p = sheet.get_style(p_name)
+                f.write('\n')
+            f.write('\n')
+        f.write('\n')
+        f.close()
+            
+    def parse(self):
+        """
+        Loads the StyleSheets from the associated file, if it exists.
+        """
+        try:
+            p = make_parser()
+            p.setContentHandler(SheetParser(self))
+            p.parse('file://' + self.file)
+        except (IOError,OSError,SAXParseException):
+            pass
+        
+#------------------------------------------------------------------------
+#
+# StyleSheet
+#
+#------------------------------------------------------------------------
+class StyleSheet:
+    """
+    A collection of named paragraph styles.
+    """
+    
+    def __init__(self,obj=None):
+        """
+        Creates a new empty StyleSheet.
+
+        obj - if not None, creates the StyleSheet from the values in
+              obj, instead of creating an empty StyleSheet
+        """
+        self.style_list = {}
+        self.name = ""
+        if obj != None:
+            for style_name in obj.style_list.keys():
+                style = obj.style_list[style_name]
+                self.style_list[style_name] = ParagraphStyle(style)
+
+    def set_name(self,name):
+        self.name = name
+
+    def get_name(self):
+        return self.name
+
+    def clear(self):
+        "Removes all paragraph styles from the StyleSheet"
+        self.style_list = {}
+
+    def add_style(self,name,style):
+        """
+        Adds a paragraph style to the style sheet.
+
+        name - name of the ParagraphStyle
+        style - ParagraphStyle instance to be added.
+        """
+        self.style_list[name] = ParagraphStyle(style)
+
+    def get_names(self):
+        "Returns the the list of paragraph names in the StyleSheet"
+        return self.style_list.keys()
+
+    def get_styles(self):
+        "Returns the paragraph name/ParagraphStyle map"
+        return self.style_list
+
+    def get_style(self,name):
+        """
+        Returns the ParagraphStyle associated with the name
+
+        name - name of the ParagraphStyle that is wanted
+        """
+        return self.style_list[name]
+
+#-------------------------------------------------------------------------
+#
+# SheetParser
+#
+#-------------------------------------------------------------------------
+class SheetParser(handler.ContentHandler):
+    """
+    SAX parsing class for the StyleSheetList XML file.
+    """
+    
+    def __init__(self,sheetlist):
+        """
+        Creates a SheetParser class that populates the passed StyleSheetList
+        class.
+
+        sheetlist - StyleSheetList instance to be loaded from the file.
+        """
+        handler.ContentHandler.__init__(self)
+        self.sheetlist = sheetlist
+        self.f = None
+        self.p = None
+        self.s = None
+        self.sname = None
+        self.pname = None
+        
+    def startElement(self,tag,attrs):
+        """
+        Overridden class that handles the start of a XML element
+        """
+        if tag == "sheet":
+            self.s = StyleSheet(self.sheetlist.map["default"])
+            self.sname = attrs['name']
+        elif tag == "font":
+            self.f = FontStyle()
+            self.f.set_type_face(int(attrs['face']))
+            self.f.set_size(int(attrs['size']))
+            self.f.set_italic(int(attrs['italic']))
+            self.f.set_bold(int(attrs['bold']))
+            self.f.set_underline(int(attrs['underline']))
+            self.f.set_color(cnv2color(attrs['color']))
+        elif tag == "para":
+            self.p.set_right_margin(Utils.gfloat(attrs['rmargin']))
+            self.p.set_left_margin(Utils.gfloat(attrs['lmargin']))
+            self.p.set_first_indent(Utils.gfloat(attrs['first']))
+            self.p.set_padding(Utils.gfloat(attrs['pad']))
+            self.p.set_alignment(int(attrs['align']))
+            self.p.set_right_border(int(attrs['rborder']))
+            self.p.set_header_level(int(attrs['level']))
+            self.p.set_left_border(int(attrs['lborder']))
+            self.p.set_top_border(int(attrs['tborder']))
+            self.p.set_bottom_border(int(attrs['bborder']))
+            self.p.set_background_color(cnv2color(attrs['bgcolor']))
+        elif tag == "style":
+            self.p = ParagraphStyle()
+            self.pname = attrs['name']
+
+    def endElement(self,tag):
+        "Overridden class that handles the start of a XML element"
+        if tag == "style":
+            self.p.set_font(self.f)
+            self.s.add_style(self.pname,self.p)
+        elif tag == "sheet":
+            self.sheetlist.set_style_sheet(self.sname,self.s)
+
+#------------------------------------------------------------------------
+#
+# GraphicsStyle
+#
+#------------------------------------------------------------------------
+class GraphicsStyle:
+    def __init__(self,obj=None):
+        if obj:
+            self.height = obj.height
+            self.width = obj.width
+            self.para_name = obj.para_name
+            self.shadow = obj.shadow
+	    self.color = obj.color
+            self.fill_color = obj.fill_color
+            self.lwidth = obj.lwidth
+            self.lstyle = obj.lstyle
+        else:
+            self.height = 0
+            self.width = 0
+            self.para_name = ""
+            self.shadow = 0
+            self.lwidth = 0.5
+            self.color = (0,0,0)
+            self.fill_color = (255,255,255)
+            self.lstyle = SOLID
+
+    def set_line_width(self,val):
+        self.lwidth = val
+
+    def get_line_width(self):
+        return self.lwidth
+
+    def get_line_style(self):
+        return self.lstyle
+
+    def set_line_style(self,val):
+        self.lstyle = val
+
+    def set_height(self,val):
+        self.height = val
+
+    def set_width(self,val):
+        self.width = val
+
+    def set_paragraph_style(self,val):
+        self.para_name = val
+
+    def set_shadow(self,val):
+        self.shadow = val
+
+    def set_color(self,val):
+        self.color = val
+
+    def set_fill_color(self,val):
+        self.fill_color = val
+
+    def get_height(self):
+        return self.height
+
+    def get_width(self):
+	return self.width
+
+    def get_paragraph_style(self):
+        return self.para_name
+
+    def get_shadow(self):
+        return self.shadow
+
+    def get_color(self):
+        return self.color
+
+    def get_fill_color(self):
+        return self.fill_color
+
+#------------------------------------------------------------------------
+#
+# TextDoc
+#
+#------------------------------------------------------------------------
+class BaseDoc:
+    """
+    Base class for text document generators. Different output formats,
+    such as OpenOffice, AbiWord, and LaTeX are derived from this base
+    class, providing a common interface to all document generators.
+    """
+    def __init__(self,styles,paper_type,template,orientation=PAPER_PORTRAIT):
+        """
+        Creates a TextDoc instance, which provides a document generation
+        interface. This class should never be instantiated directly, but
+        only through a derived class.
+
+        styles      - StyleSheet containing the paragraph styles used.
+        paper_type  - PaperStyle instance containing information about
+                      the paper. If set to None, then the document is
+                      not a page oriented document (e.g. HTML)
+        template    - Format template for document generators that are
+                      not page oriented.
+        orientation - page orientation, either PAPER_PORTRAIT or
+                      PAPER_LANDSCAPE
+        """
+        self.orientation = orientation
+        self.template = template
+        if orientation == PAPER_PORTRAIT:
+            self.width = paper_type.get_width()
+            self.height = paper_type.get_height()
+        else:
+            self.width = paper_type.get_height()
+            self.height = paper_type.get_width()
+        self.paper = paper_type
+        self.tmargin = 2.54
+        self.bmargin = 2.54
+        self.lmargin = 2.54
+        self.rmargin = 2.54
+        self.title = ""
+        self.owner = ''
+                
+	self.draw_styles = {}
+        self.font = FontStyle()
+        self.style_list = styles.get_styles()
+	self.table_styles = {}
+        self.cell_styles = {}
+        self.name = ""
+        self.photo_list = []
+        self.print_req = 0
+        self.mode = TEXT_MODE
+
+    def set_mode(self, mode):
+        self.mode = mode
+        
+    def print_requested (self):
+        self.print_req = 1
+
+    def set_owner(self,owner):
+        """
+        Sets the name of the owner of the document.
+
+        owner - User's name
+        """
+        self.owner = owner
+        
+    def add_photo(self,name,align,w_cm,h_cm):
+        """
+        Adds a photo of the specified width (in centimeters)
+
+        name  - filename of the image to add
+        align - alignment of the image. Valid values are 'left', 'right',
+                'center', and 'single'
+        w_cm  - width in centimeters
+        h_cm  - height in centimeters
+        """
+        pass
+    
+    def get_usable_width(self):
+        """
+        Returns the width of the text area in centimeters. The value is
+        the page width less the margins.
+        """
+        return self.width - (self.rmargin + self.lmargin)
+
+    def get_usable_height(self):
+        """
+        Returns the height of the text area in centimeters. The value is
+        the page height less the margins.
+        """
+        return self.height - (self.tmargin + self.bmargin)
+
+    def creator(self,name):
+        "Returns the owner name"
+        self.name = name
+
+    def set_title(self,name):
+        """
+        Sets the title of the document.
+
+        name - Title of the document
+        """
+        self.title = name
+
+    def add_draw_style(self,name,style):
+        self.draw_styles[name] = GraphicsStyle(style)
+
+    def add_table_style(self,name,style):
+        """
+        Adds the TableStyle with the specfied name.
+
+        name  - name of the table style
+        style - TableStyle instance to be added
+        """
+        self.table_styles[name] = TableStyle(style)
+
+    def add_cell_style(self,name,style):
+        """
+        Adds the TableCellStyle with the specfied name.
+
+        name  - name of the table cell style
+        style - TableCellStyle instance to be added
+        """
+        self.cell_styles[name] = TableCellStyle(style)
+
+    def open(self,filename):
+        """
+        Opens the document.
+
+        filename - path name of the file to create
+        """
+        pass
+
+    def close(self):
+        "Closes the document"
+        pass
+
+    def line_break(self):
+        "Forces a line break within a paragraph"
+	pass
+
+    def page_break(self, mode=-1):
+        "Forces a page break, creating a new page"
+        pass
+
+    def start_bold(self):
+        pass
+
+    def end_bold(self):
+        pass
+
+    def start_superscript(self):
+        pass
+
+    def end_superscript(self):
+        pass
+
+    def start_listing(self,style_name):
+        """
+	Starts a new listing block, using the specified style name.
+
+        style_name - name of the ParagraphStyle to use for the block.
+	"""
+        pass
+
+    def end_listing(self):
+        pass
+
+    def start_paragraph(self,style_name,leader=None):
+        """
+        Starts a new paragraph, using the specified style name.
+
+        style_name - name of the ParagraphStyle to use for the paragraph.
+        leader     - Leading text for a paragraph. Typically used for numbering.
+        """
+        pass
+
+    def end_paragraph(self):
+        "Ends the current parsgraph"
+        pass
+
+    def start_table(self,name,style_name):
+        """
+        Starts a new table.
+
+        name       - Unique name of the table.
+        style_name - TableStyle to use for the new table
+        """
+        pass
+
+    def end_table(self):
+        "Ends the current table"
+        pass
+
+    def start_row(self):
+        "Starts a new row on the current table"
+        pass
+
+    def end_row(self):
+        "Ends the current row on the current table"
+        pass
+
+    def start_cell(self,style_name,span=1):
+        """
+        Starts a new table cell, using the paragraph style specified.
+
+        style_name - TableCellStyle to use for the cell
+        span       - number of columns to span
+        """
+        pass
+
+    def end_cell(self):
+        "Ends the current table cell"
+        pass
+
+    def horizontal_line(self):
+        "Creates a horizontal line"
+        pass
+
+    def write_text(self,text):
+        """
+        Writes the text in the current paragraph. Should only be used after a
+        start_paragraph and before an end_paragraph.
+
+        text - text to write.
+        """
+        pass
+
+    def write_cmdstr(self,text):
+        """
+        Writes the text in the current paragraph. Should only be used after a
+        start_paragraph and before an end_paragraph.
+
+        text - text to write.
+        """
+        pass
+
+    def draw_arc(self,style,x1,y1,x2,y2,angle,extent):
+        pass
+
+    def draw_path(self,style,path):
+        pass
+    
+    def draw_box(self,style,text,x,y):
+	pass
+
+    def write_at(self,style,text,x,y):
+	pass
+
+    def draw_bar(self,style,x1,y1,x2,y2):
+        pass
+
+    def draw_text(self,style,text,x1,y1):
+        pass
+
+    def center_text(self,style,text,x1,y1):
+        pass
+
+    def rotate_text(self,style,text,x,y,angle):
+        pass
+    
+    def draw_line(self,style,x1,y1,x2,y2):
+	pass
+
+    def draw_wedge(self, style, centerx, centery, radius, start_angle,
+                   end_angle, short_radius=0):
+
+        while end_angle < start_angle:
+            end_angle += 360
+
+        p = []
+        
+        degreestoradians = pi/180.0
+        radiansdelta = degreestoradians/2
+        sangle = start_angle*degreestoradians
+        eangle = end_angle*degreestoradians
+        while eangle=sangle:
+                x = centerx + cos(angle)*short_radius
+                y = centery + sin(angle)*short_radius
+                p.append((x,y))
+                angle = angle-radiansdelta
+        self.draw_path(style,p)
+
+        delta = (eangle - sangle)/2.0
+        rad = short_radius + (radius-short_radius)/2.0
+
+        return ( (centerx + cos(sangle+delta) * rad),
+                 (centery + sin(sangle+delta) * rad))
+    
+    def start_path(self,style,x,y):
+        pass
+
+    def line_to(self,x,y):
+        pass
+
+    def arc_to(self,x,y,angle,extent):
+        pass
+
+    def end_path(self):
+        pass
diff --git a/gramps2/src/docgen/OpenOfficeDoc.py b/gramps2/src/docgen/OpenOfficeDoc.py
index c4e1c2d4c..d45c7ea75 100644
--- a/gramps2/src/docgen/OpenOfficeDoc.py
+++ b/gramps2/src/docgen/OpenOfficeDoc.py
@@ -35,7 +35,7 @@ import time
 #
 #-------------------------------------------------------------------------
 import Errors
-import TextDoc
+import BaseDoc
 import const
 import Plugins
 import ImgManip
@@ -52,16 +52,25 @@ from gettext import gettext as _
 # OpenOfficeDoc
 #
 #-------------------------------------------------------------------------
-class OpenOfficeDoc(TextDoc.TextDoc):
+class OpenOfficeDoc(BaseDoc.BaseDoc):
 
-    def __init__(self,styles,type,template,orientation):
-        TextDoc.TextDoc.__init__(self,styles,type,template,orientation)
+    def __init__(self,styles,type,template,orientation=BaseDoc.PAPER_PORTRAIT):
+        BaseDoc.BaseDoc.__init__(self,styles,type,template,orientation)
         self.f = None
         self.filename = None
         self.level = 0
         self.time = "0000-00-00T00:00:00"
         self.new_page = 0
         self.new_cell = 0
+        self.page = 0
+        self.first_page = 1
+
+    def set_mode(self, mode):
+        self.mode = mode
+        if self.first_page == 0:
+            self.page_break(mode)
+        else:
+            self.first_page = 0
 
     def open(self,filename):
         t = time.localtime(time.time())
@@ -80,8 +89,10 @@ class OpenOfficeDoc(TextDoc.TextDoc):
             self.f = open(self.content_xml,"wb")
         except IOError,msg:
             errmsg = "%s\n%s" % (_("Could not create %s") % self.content_xml, msg)
+            pass
             raise Errors.ReportError(errmsg)
         except:
+            pass
             raise Errors.ReportError("Could not create %s" % self.content_xml)
 
         self.f.write('\n')
@@ -113,10 +124,44 @@ class OpenOfficeDoc(TextDoc.TextDoc):
         self.f.write('style:font-pitch="variable"/>\n')
         self.f.write('\n')
         self.f.write('\n')
+        self.f.write('\n')
+        self.f.write('\n')
+        self.f.write('\n')
         self.f.write('')
         self.f.write('')
         self.f.write('\n')
 
+	for style_name in self.draw_styles.keys():
+            style = self.draw_styles[style_name]
+            self.f.write('\n')
+	    self.f.write('\n')
+  	    self.f.write('\n')
+
         for style_name in self.style_list.keys():
 	    style = self.style_list[style_name]
             self.f.write('\n')
@@ -420,18 +465,18 @@ class OpenOfficeDoc(TextDoc.TextDoc):
                 self.f.write('fo:keep-with-next="true" ')
 
             align = style.get_alignment()
-	    if align == TextDoc.PARA_ALIGN_LEFT:
+	    if align == BaseDoc.PARA_ALIGN_LEFT:
 	       self.f.write('fo:text-align="start" ')
-            elif align == TextDoc.PARA_ALIGN_RIGHT:
+            elif align == BaseDoc.PARA_ALIGN_RIGHT:
                self.f.write('fo:text-align="end" ')
-            elif align == TextDoc.PARA_ALIGN_CENTER:
+            elif align == BaseDoc.PARA_ALIGN_CENTER:
                self.f.write('fo:text-align="center" ')
                self.f.write('style:justify-single-word="false" ')
             else:
                self.f.write('fo:text-align="justify" ')
                self.f.write('style:justify-single-word="false" ')
             font = style.get_font()
-            if font.get_type_face() == TextDoc.FONT_SANS_SERIF:
+            if font.get_type_face() == BaseDoc.FONT_SANS_SERIF:
                 self.f.write('style:font-name="Arial" ')
             else:
                 self.f.write('style:font-name="Times New Roman" ')
@@ -474,7 +519,7 @@ class OpenOfficeDoc(TextDoc.TextDoc):
         self.f.write('\n')
         self.f.write('\n')
+	self.f.write('\n')
+	self.f.write('\n')
+	self.f.write('\n')
+	self.f.write('\n')
+	self.f.write('\n')
+	self.f.write('\n')
+	self.f.write('\n')
+	self.f.write('\n')
         self.f.write('\n')
         self.f.write('\n')
 	self.f.close()
 
-    def page_break(self):
-        self.new_page = 1
+    def page_break(self, graphics=-1):
+        if self.mode == BaseDoc.GRAPHICS_MODE:
+            self.f.write('\n')
+        if graphics != -1:
+            self.mode = graphics
+            
+        if self.mode == BaseDoc.GRAPHICS_MODE:
+            self.page = self.page + 1
+            self.f.write('')
+        else:
+            self.new_page = 1
         
     def start_paragraph(self,style_name,leader=None):
 	style = self.style_list[style_name]
 	self.level = style.get_header_level()
         if self.new_page == 1:
-            self.new_page = 0
+            self.new_page = 0 
             name = "NL%s" % style_name
         else:
             name = style_name
@@ -530,10 +598,10 @@ class OpenOfficeDoc(TextDoc.TextDoc):
         self.new_cell = 1
 
     def write_text(self,text):
-        text = string.replace(text,'&','&');       # Must be first
-        text = string.replace(text,'<','<');
-        text = string.replace(text,'>','>');
-        text = string.replace(text,'\n','')
+        text = text.replace('&','&')       # Must be first
+        text = text.replace('<','<')
+        text = text.replace('>','>')
+        text = text.replace('\n','')
         text = text.replace('<super>','')
         text = text.replace('</super>','')
 	self.f.write(text)
@@ -547,8 +615,10 @@ class OpenOfficeDoc(TextDoc.TextDoc):
             errmsg = "%s\n%s" % (_("Could not create %s") % self.manifest_xml, msg)
             raise Errors.ReportError(errmsg)
         except:
+            pass
             raise Errors.ReportError(_("Could not create %s") % self.manifest_xml)
 
+
 	self.f.write('\n')
 	self.f.write('')
@@ -583,6 +653,7 @@ class OpenOfficeDoc(TextDoc.TextDoc):
             errmsg = "%s\n%s" % (_("Could not create %s") % self.meta_xml, msg)
             raise Errors.ReportError(errmsg)
         except:
+            pass
             raise Errors.ReportError(_("Could not create %s") % self.meta_xml)
 
 	self.f.write('\n')
@@ -620,10 +691,162 @@ class OpenOfficeDoc(TextDoc.TextDoc):
 	self.f.write('\n')
 	self.f.close()
 
+    def rotate_text(self,style,text,x,y,angle):
+
+        stype = self.draw_styles[style]
+        pname = stype.get_paragraph_style()
+        p = self.style_list[pname]
+	font = p.get_font()
+        size = font.get_size()
+
+        height = size*(len(text))
+        width = 0
+        for line in text:
+            width = max(width,FontScale.string_width(font,line))
+        wcm = (width/72.0)*2.54
+        hcm = (height/72.0)*2.54
+
+        rangle = -((pi/180.0) * angle)
+
+        self.f.write('')
+        self.f.write('' % pname)
+        self.write_text(string.join(text,'\n'))
+        self.f.write('\n')
+
+    def draw_path(self,style,path):
+        stype = self.draw_styles[style]
+
+        minx = 9e12
+        miny = 9e12
+        maxx = 0
+        maxy = 0
+
+        for point in path:
+            minx = min(point[0],minx)
+            miny = min(point[1],miny)
+            maxx = max(point[0],maxx)
+            maxy = max(point[1],maxy)
+
+        self.f.write('\n')
+
+    def draw_line(self,style,x1,y1,x2,y2):
+        x1 = x1 + self.lmargin
+        x2 = x2 + self.lmargin
+        y1 = y1 + self.tmargin
+        y2 = y2 + self.tmargin
+	box_style = self.draw_styles[style]
+
+        self.f.write('\n')
+
+    def draw_text(self,style,text,x,y):
+        x = x + self.lmargin
+        y = y + self.tmargin
+	box_style = self.draw_styles[style]
+	para_name = box_style.get_paragraph_style()
+
+        pstyle = self.style_list[para_name]
+        font = pstyle.get_font()
+        sw = FontScale.string_width(font,text)*1.3
+
+	self.f.write('' % float(y))
+        self.f.write('')
+        self.f.write('' % para_name)
+        self.f.write(text)
+        self.f.write('')
+        self.f.write('\n')
+
+    def draw_bar(self,style,x,y,x2,y2):
+        x = x + self.lmargin
+        x2 = x2 + self.lmargin
+        y = y + self.tmargin
+        y2 = y2 + self.tmargin
+
+	box_style = self.draw_styles[style]
+	para_name = box_style.get_paragraph_style()
+
+	self.f.write('' % float(y))
+        self.f.write('\n')
+
+    def draw_box(self,style,text,x,y):
+        x = x + self.lmargin
+        y = y + self.tmargin
+	box_style = self.draw_styles[style]
+	para_name = box_style.get_paragraph_style()
+
+	self.f.write('')
+            text = string.replace(text,'\n','')
+            self.f.write('>\n')
+  	    self.f.write('')
+	    self.f.write('' % para_name)
+	    self.f.write(text)
+            self.f.write('\n')
+            self.f.write('\n')
+        else:
+            self.f.write('/>\n')
+
 print_label = None
 if os.access ("/usr/bin/oowriter", os.X_OK):
     print_label = _("Open in OpenOffice.org")
-
+     
+#--------------------------------------------------------------------------
+#
+# Register plugins
+#
+#--------------------------------------------------------------------------
 Plugins.register_text_doc(_("OpenOffice.org Writer"),OpenOfficeDoc,1,1,1,
-                          ".sxw",print_label)
+                           ".sxw",print_label)
 Plugins.register_book_doc(_("OpenOffice.org Writer"),OpenOfficeDoc,1,1,1,".sxw")
+