From 3c40fcbd9e5ebf9dbd9756e9f5075d7b50256694 Mon Sep 17 00:00:00 2001 From: Don Allingham Date: Tue, 29 Jan 2002 00:44:15 +0000 Subject: [PATCH] New plugin system for document generators svn: r733 --- src/AutoComp.py | 5 +- src/Plugins.py | 230 ++++++++++++-- src/Report.py | 14 +- src/TextDoc.py | 3 +- src/const.py | 1 + src/docgen/AbiWordDoc.py | 242 ++++++++++++++ src/docgen/HtmlDoc.py | 340 ++++++++++++++++++++ src/docgen/KwordDoc.py | 441 ++++++++++++++++++++++++++ src/docgen/LaTeXDoc.py | 136 ++++++++ src/docgen/OpenDrawDoc.py | 449 ++++++++++++++++++++++++++ src/docgen/OpenOfficeDoc.py | 579 ++++++++++++++++++++++++++++++++++ src/docgen/OpenSpreadSheet.py | 457 +++++++++++++++++++++++++++ src/docgen/PSDrawDoc.py | 168 ++++++++++ src/docgen/PdfDoc.py | 284 +++++++++++++++++ src/docgen/PdfDrawDoc.py | 185 +++++++++++ src/docgen/RTFDoc.py | 525 ++++++++++++++++++++++++++++++ src/gramps_main.py | 2 + src/plugins/AncestorChart.py | 2 +- 18 files changed, 4019 insertions(+), 44 deletions(-) create mode 100644 src/docgen/AbiWordDoc.py create mode 100644 src/docgen/HtmlDoc.py create mode 100644 src/docgen/KwordDoc.py create mode 100644 src/docgen/LaTeXDoc.py create mode 100644 src/docgen/OpenDrawDoc.py create mode 100644 src/docgen/OpenOfficeDoc.py create mode 100644 src/docgen/OpenSpreadSheet.py create mode 100644 src/docgen/PSDrawDoc.py create mode 100644 src/docgen/PdfDoc.py create mode 100644 src/docgen/PdfDrawDoc.py create mode 100644 src/docgen/RTFDoc.py diff --git a/src/AutoComp.py b/src/AutoComp.py index 2f2b43b0d..1b18763be 100644 --- a/src/AutoComp.py +++ b/src/AutoComp.py @@ -27,7 +27,10 @@ import string import gtk class AutoComp: - + """ + Allows allow completion of the GtkEntry widget with the entries + in the passed string list. + """ def __init__(self,widget,plist): self.entry = widget self.nlist = [("","")] diff --git a/src/Plugins.py b/src/Plugins.py index 75eae2793..e9c9474e9 100644 --- a/src/Plugins.py +++ b/src/Plugins.py @@ -18,20 +18,26 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # +""" +The core of the GRAMPS plugin system. This module provides tasks to load +plugins from specfied directories, build menus for the different categories, +and provide dialog to select and execute plugins. + +Plugins are divided into several categories. This are: reports, tools, +filters, importer, exporters, and document generators. +""" + #------------------------------------------------------------------------- # -# +# GTK libraries # #------------------------------------------------------------------------- import gtk import libglade -from intl import gettext -_ = gettext - #------------------------------------------------------------------------- # -# +# Standard Python modules # #------------------------------------------------------------------------- import os @@ -40,15 +46,18 @@ from re import compile #------------------------------------------------------------------------- # -# +# GRAMPS modules # #------------------------------------------------------------------------- import const import utils +import Config +from intl import gettext +_ = gettext #------------------------------------------------------------------------- # -# +# Global lists # #------------------------------------------------------------------------- _reports = [] @@ -59,10 +68,12 @@ _success = [] _failed = [] _attempt = [] _loaddir = [] +_textdoc = [] +_drawdoc = [] #------------------------------------------------------------------------- # -# +# Constants # #------------------------------------------------------------------------- DOCSTRING = "d" @@ -71,36 +82,45 @@ TASK = "f" TITLE = "t" STATUS = "s" -pymod = compile(r"^(.*)\.py$") - #------------------------------------------------------------------------- # -# +# ReportPlugins interface class # #------------------------------------------------------------------------- class ReportPlugins: + """Displays the dialog box that allows the user to select the + report that is desired.""" def __init__(self,db,active): + """Display the dialog box, and build up the list of available + reports. This is used to build the selection tree on the left + hand side of the dailog box.""" + self.db = db self.active = active self.dialog = libglade.GladeXML(const.pluginsFile,"report") self.dialog.signal_autoconnect({ - "on_report_apply_clicked" : self.on_report_apply_clicked, - "on_report_ok_clicked" : self.on_report_apply_clicked, + "on_report_apply_clicked" : self.on_apply_clicked, + "on_report_ok_clicked" : self.on_apply_clicked, "destroy_passed_object" : utils.destroy_passed_object }) tree = self.dialog.get_widget("tree1") self.run_tool = None - build_tree(tree,_reports,self.on_report_node_selected) + build_tree(tree,_reports,self.on_node_selected) + + def on_apply_clicked(self,obj): + """Execute the selected report""" - def on_report_apply_clicked(self,obj): utils.destroy_passed_object(obj) if self.run_tool: self.run_tool(self.db,self.active) - def on_report_node_selected(self,obj): + def on_node_selected(self,obj): + """Updates the informational display on the right hand side of + the dialog box with the description of the selected report""" + doc = obj.get_data(DOCSTRING) xpm = obj.get_data(IMAGE) status = ": %s" % obj.get_data(STATUS) @@ -119,11 +139,18 @@ class ReportPlugins: #------------------------------------------------------------------------- # -# +# ToolPlugins interface class # #------------------------------------------------------------------------- class ToolPlugins: + """Displays the dialog box that allows the user to select the tool + that is desired.""" + def __init__(self,db,active,update): + """Display the dialog box, and build up the list of available + reports. This is used to build the selection tree on the left + hand side of the dailog box.""" + self.db = db self.active = active self.update = update @@ -140,11 +167,16 @@ class ToolPlugins: build_tree(tree,_tools,self.on_node_selected) def on_apply_clicked(self,obj): + """Execute the selected tool.""" + utils.destroy_passed_object(obj) if self.run_tool: self.run_tool(self.db,self.active,self.update) def on_node_selected(self,obj): + """Updates the informational display on the right hand side of + the dialog box with the description of the selected tool.""" + doc = obj.get_data(DOCSTRING) title = obj.get_data(TITLE) @@ -154,10 +186,20 @@ class ToolPlugins: #------------------------------------------------------------------------- # -# +# build_tree # #------------------------------------------------------------------------- def build_tree(tree,list,task): + """Populates a GtkTree with each menu item assocated with a entry + in the lists. The list must consist of a tuples with the following + format: + + (task_to_call, category of report, report name, description, image, status) + + Items in the same category are grouped under the same submen. The + task_to_call is bound to the 'select' callback of the menu entry.""" + + # build the tree items and group together based on the category name item_hash = {} for report in list: item = gtk.GtkTreeItem(report[2]) @@ -173,6 +215,8 @@ def build_tree(tree,list,task): else: item_hash[report[1]] = [item] + # add a submenu for each category, and populate it with the GtkTreeItems + # that are associated with it. key_list = item_hash.keys() key_list.sort() for key in key_list: @@ -189,19 +233,38 @@ def build_tree(tree,list,task): #------------------------------------------------------------------------- # -# +# load_plugins # #------------------------------------------------------------------------- def load_plugins(dir): + """Searches the specified directory, and attempts to load any python + modules that it finds, adding name to the _attempts list. If the module + successfully loads, it is added to the _success list. Each plugin is + responsible for registering itself in the correct manner. No attempt + is done in this routine to register the tasks.""" + global _success,_failed,_attempt,_loaddir + # if the directory does not exist, do nothing if not os.path.isdir(dir): return + # if the path has not already been loaded, save it in the _loaddir + # list for use on reloading + if dir not in _loaddir: _loaddir.append(dir) + # add the directory to the python search path sys.path.append(dir) + + pymod = compile(r"^(.*)\.py$") + + # loop through each file in the directory, looking for files that + # have a .py extention, and attempt to load the file. If it succeeds, + # add it to the _success list. If it fails, add it to the _failure + # list + for file in os.listdir(dir): name = os.path.split(file) match = pymod.match(name[1]) @@ -218,7 +281,19 @@ def load_plugins(dir): traceback.print_exc() _failed.append(plugin) +#------------------------------------------------------------------------- +# +# reload_plugins +# +#------------------------------------------------------------------------- def reload_plugins(obj): + """Treated as a callback, causes all plugins to get reloaded. This is + useful when writing and debugging a plugin""" + + pymod = compile(r"^(.*)\.py$") + + # attempt to reload all plugins that have succeeded + # in the past for plugin in _success: try: reload(plugin) @@ -227,6 +302,9 @@ def reload_plugins(obj): import traceback traceback.print_exc() _failed.append(plugin) + + # attempt to load the plugins that have failed in the past + for plugin in _failed: try: __import__(plugin) @@ -236,12 +314,15 @@ def reload_plugins(obj): traceback.print_exc() _failed.append(plugin) + # attempt to load any new files found for dir in _loaddir: for file in os.listdir(dir): name = os.path.split(file) match = pymod.match(name[1]) if not match: continue + if file in _attempt: + return _attempt.append(file) plugin = match.groups()[0] try: @@ -259,9 +340,11 @@ def reload_plugins(obj): # #------------------------------------------------------------------------- def register_export(task, name): + """Register an export filter, taking the task and name""" _exports.append((task, name)) def register_import(task, name): + """Register an import filter, taking the task and name""" _imports.append((task, name)) def register_report(task, name, @@ -269,28 +352,36 @@ def register_report(task, name, description=_("No description was provided"), xpm=None, status=_("Unknown")): + """Register a report with the plugin system""" + if xpm == None: - xpm_data = no_image() - elif type(xpm) == type([]): - xpm_data = xpm - else: - xpm_data = xpm - - _reports.append((task, category, name, description, xpm_data, status)) + xpm = no_image() + _reports.append((task, category, name, description, xpm, status)) def register_tool(task, name, category=_("Uncategorized"), description=_("No description was provided"), xpm=None, status=_("Unknown")): + """Register a tool with the plugin system""" if xpm == None: - xpm_data = no_image() - elif type(xpm) == type([]): - xpm_data = xpm - else: - xpm_data = xpm + xpm = no_image() + _tools.append((task, category, name, description, xpm, status)) - _tools.append((task, category, name, description, xpm_data, status)) + +def register_text_doc(name,classref, table, paper, style): + """Register a text document generator""" + for n in _textdoc: + if n[0] == name: + return + _textdoc.append((name,classref,table,paper,style)) + +def register_draw_doc(name,classref): + """Register a drawing document generator""" + for n in _drawdoc: + if n[0] == name: + return + _drawdoc.append((name,classref)) #------------------------------------------------------------------------- # @@ -326,12 +417,27 @@ def build_menu(top_menu,list,callback): submenu.append(subentry) top_menu.set_submenu(report_menu) +#------------------------------------------------------------------------- +# +# build_report_menu +# +#------------------------------------------------------------------------- def build_report_menu(top_menu,callback): build_menu(top_menu,_reports,callback) +#------------------------------------------------------------------------- +# +# build_tools_menu +# +#------------------------------------------------------------------------- def build_tools_menu(top_menu,callback): build_menu(top_menu,_tools,callback) +#------------------------------------------------------------------------- +# +# build_export_menu +# +#------------------------------------------------------------------------- def build_export_menu(top_menu,callback): myMenu = gtk.GtkMenu() @@ -342,6 +448,11 @@ def build_export_menu(top_menu,callback): myMenu.append(item) top_menu.set_submenu(myMenu) +#------------------------------------------------------------------------- +# +# build_import_menu +# +#------------------------------------------------------------------------- def build_import_menu(top_menu,callback): myMenu = gtk.GtkMenu() @@ -352,13 +463,66 @@ def build_import_menu(top_menu,callback): myMenu.append(item) top_menu.set_submenu(myMenu) +#------------------------------------------------------------------------- +# +# get_text_doc_menu +# +#------------------------------------------------------------------------- +def get_text_doc_menu(main_menu,tables,callback,obj=None): + + index = 0 + myMenu = gtk.GtkMenu() + _textdoc.sort() + for item in _textdoc: + if tables and item[2] == 0: + continue + name = item[0] + menuitem = gtk.GtkMenuItem(name) + menuitem.set_data("name",item[1]) + menuitem.set_data("styles",item[4]) + menuitem.set_data("paper",item[3]) + menuitem.set_data("obj",obj) + if callback: + menuitem.connect("activate",callback) + menuitem.show() + myMenu.append(menuitem) + if name == Config.output_preference: + myMenu.set_active(index) + callback(menuitem) + index = index + 1 + main_menu.set_menu(myMenu) #------------------------------------------------------------------------- # -# +# get_draw_doc_menu +# +#------------------------------------------------------------------------- +def get_draw_doc_menu(main_menu,callback=None,obj=None): + + index = 0 + myMenu = gtk.GtkMenu() + for (name,classref) in _drawdoc: + menuitem = gtk.GtkMenuItem(name) + menuitem.set_data("name",classref) + menuitem.set_data("obj",obj) + if callback: + menuitem.connect("activate",callback) + menuitem.show() + myMenu.append(menuitem) + if name == Config.output_preference: + myMenu.set_active(index) + if callback: + callback(menuitem) + index = index + 1 + main_menu.set_menu(myMenu) + +#------------------------------------------------------------------------- +# +# no_image # #------------------------------------------------------------------------- def no_image(): + """Returns XPM data for basic 48x48 icon""" return [ "48 48 5 1", " c None", diff --git a/src/Report.py b/src/Report.py index c6e27b7af..9da4051d1 100644 --- a/src/Report.py +++ b/src/Report.py @@ -28,6 +28,7 @@ import sort import string import utils import intl +import Plugins _ = intl.gettext @@ -35,7 +36,6 @@ from TextDoc import * from StyleEditor import * import Config -import FindDoc import PaperMenu from gtk import * @@ -898,14 +898,13 @@ class TextReportDialog(ReportDialog): """Build a menu of document types that are appropriate for this text report. This menu will be generated based upon whether the document requires table support, etc.""" - FindDoc.get_text_doc_menu(self.format_menu, self.doc_uses_tables(), + Plugins.get_text_doc_menu(self.format_menu, self.doc_uses_tables(), self.doc_type_changed) def make_document(self): """Create a document of the type requested by the user.""" - self.doc = FindDoc.make_text_doc(self.selected_style,self.format, - self.paper,self.orien, - self.template_name) + self.doc = self.format(self.selected_style,self.paper, + self.template_name,self.orien) #------------------------------------------------------------------------ # @@ -942,9 +941,8 @@ class DrawReportDialog(ReportDialog): def make_doc_menu(self): """Build a menu of document types that are appropriate for this drawing report.""" - FindDoc.get_draw_doc_menu(self.format_menu) + Plugins.get_draw_doc_menu(self.format_menu) def make_document(self): """Create a document of the type requested by the user.""" - self.doc = FindDoc.make_draw_doc(self.selected_style,self.format, - self.paper,self.orien) + self.doc = self.format(self.selected_style,self.paper,self.orien) diff --git a/src/TextDoc.py b/src/TextDoc.py index 7169a33a9..22af3d7bd 100644 --- a/src/TextDoc.py +++ b/src/TextDoc.py @@ -572,8 +572,9 @@ class SheetParser(handler.ContentHandler): # #------------------------------------------------------------------------ class TextDoc: - def __init__(self,styles,type,orientation=PAPER_PORTRAIT): + def __init__(self,styles,type,template,orientation=PAPER_PORTRAIT): self.orientation = orientation + self.template = template if orientation == PAPER_PORTRAIT: self.width = type.get_width() self.height = type.get_height() diff --git a/src/const.py b/src/const.py index 771925510..0433f1946 100644 --- a/src/const.py +++ b/src/const.py @@ -74,6 +74,7 @@ findFile = "%s/find.glade" % rootDir mergeFile = "%s/mergedata.glade" % rootDir traceFile = "%s/trace.glade" % rootDir pluginsDir = "%s/plugins" % rootDir +docgenDir = "%s/docgen" % rootDir filtersDir = "%s/filters" % rootDir dataDir = "%s/data" % rootDir gtkrcFile = "%s/gtkrc" % rootDir diff --git a/src/docgen/AbiWordDoc.py b/src/docgen/AbiWordDoc.py new file mode 100644 index 000000000..4499dc023 --- /dev/null +++ b/src/docgen/AbiWordDoc.py @@ -0,0 +1,242 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2000 Donald N. Allingham +# +# 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 a TextDoc based interface to the AbiWord document format. +""" + +#------------------------------------------------------------------------- +# +# Imported Modules +# +#------------------------------------------------------------------------- +import os +import base64 + +from TextDoc import * +from latin_utf8 import latin_to_utf8 +import const +import string +import Plugins +import intl +_ = intl.gettext + +#------------------------------------------------------------------------- +# +# Attemp to import the Python Imaging Library +# +#------------------------------------------------------------------------- +try: + import PIL.Image + no_pil = 0 +except: + no_pil = 1 + +#------------------------------------------------------------------------- +# +# Class Definitions +# +#------------------------------------------------------------------------- +class AbiWordDoc(TextDoc): + """AbiWord document generator. Inherits from the TextDoc generic + document interface class.""" + + def __init__(self,styles,type,orientation): + """Initializes the AbiWordDoc class, calling the __init__ routine + of the parent TextDoc class""" + TextDoc.__init__(self,styles,type,orientation) + self.f = None + self.level = 0 + self.new_page = 0 + + def open(self,filename): + """Opens the document, writing the necessary header information. + AbiWord uses an XML format, so the document format is pretty easy + to understand""" + if filename[-4:] != ".abw": + self.filename = "%s.abw" % filename + else: + self.filename = filename + + self.f = open(self.filename,"w") + self.f.write('\n') + self.f.write('\n') + self.f.write('\n') + self.f.write('
\n') + + def close(self): + """Write the trailing information and closes the file""" + self.f.write('
\n') + if len(self.photo_list) > 0: + self.f.write('\n') + for file_tuple in self.photo_list: + file = file_tuple[0] + width = file_tuple[1] + height = file_tuple[2] + base = "/tmp/%s.png" % os.path.basename(file) + tag = string.replace(base,'.','_') + + if no_pil: + cmd = "%s -geometry %dx%d '%s' '%s'" % (const.convert,width,height,file,base) + os.system(cmd) + else: + im = PIL.Image.open(file) + im.thumbnail((width,height)) + im.save(base,"PNG") + + self.f.write('\n') + f = open(base,"rb") + base64.encode(f,self.f) + f.close() + os.unlink(base) + self.f.write('\n') + self.f.write('\n') + + self.f.write('
\n') + self.f.close() + + def add_photo(self,pos,name,x_cm,y_cm): + import gtk + import GdkImlib + + image = GdkImlib.Image(name) + scale = float(image.rgb_width)/float(image.rgb_height) + act_width = int(((x_cm * scale)*2.54)*72) + act_height = int(((y_cm * scale)*2.54)*72) + + self.photo_list.append((name,act_width,act_height)) + + base = "/tmp/%s.png" % os.path.basename(name) + tag = string.replace(base,'.','_') + + self.f.write('' % act_height) + + def start_paragraph(self,style_name,leader=None): + style = self.style_list[style_name] + self.current_style = style + self.f.write('

') + font = style.get_font() + self.f.write('') + if self.new_page == 1: + self.new_page = 0 + self.f.write('') + if leader != None: + self.f.write(leader) + self.f.write('\t') + + def page_break(self): + self.new_page = 1 + + def end_paragraph(self): + self.f.write('

\n') + + def write_text(self,text): + text = string.replace(text,'&','&'); # Must be first + text = string.replace(text,'<','<'); + text = string.replace(text,'>','>'); + self.f.write(text) + + def start_bold(self): + font = self.current_style.get_font() + self.f.write('') + + def end_bold(self): + font = self.current_style.get_font() + self.f.write('') + + +Plugins.register_text_doc(_("AbiWord"),AbiWordDoc,0,1,1) diff --git a/src/docgen/HtmlDoc.py b/src/docgen/HtmlDoc.py new file mode 100644 index 000000000..69e6131bb --- /dev/null +++ b/src/docgen/HtmlDoc.py @@ -0,0 +1,340 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2000 Donald N. Allingham +# +# 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 +# + +import os +import string +import re +import utils +import gnome.ui +import Plugins + +from intl import gettext +_ = gettext + +from TextDoc import * + +#------------------------------------------------------------------------ +# +# Attempt to load the Python Imaging Library for the handling of photos. +# +#------------------------------------------------------------------------ +try: + import PIL.Image + no_pil = 0 +except: + no_pil = 1 + +t_header_line_re = re.compile(r"(.*)(.*)(.*)", re.DOTALL|re.IGNORECASE|re.MULTILINE) + +#------------------------------------------------------------------------ +# +# Default template +# +#------------------------------------------------------------------------ +_top = [ + '\n', + '\n', + '\n', + ' \n', + ' \n', + ' \n', + ' \n', + '\n', + '\n', + ' \n' + ] + +_bottom = [ + ' \n', + '\n', + '\n' + ] + +class HtmlDoc(TextDoc): + + def __init__(self,styles,type,template,orientation,source=None): + TextDoc.__init__(self,styles,PaperStyle("",0,0),template,None) + if source == None: + self.f = None + self.filename = None + self.top = [] + self.bottom = [] + self.base = "" + + self.load_template() + self.build_header() + self.build_style_declaration() + + else: + self.f = None + self.filename = source.filename + self.template = None + self.top = source.top + self.bottom = source.bottom + self.base = source.base + self.file_header = source.file_header + self.style_declaration = source.style_declaration + self.table_styles = source.table_styles; + self.cell_styles = source.cell_styles; + + def load_template(self): + start = re.compile(r"") + stop = re.compile(r"") + top_add = 1 + bottom_add = 0 + if self.template and self.template != "": + try: + templateFile = open(self.template,"r") + for line in templateFile.readlines(): + if top_add == 1: + self.top.append(line) + match = start.search(line) + if match: + top_add = 0 + elif bottom_add == 0: + match = stop.search(line) + if match != None: + bottom_add = 1 + self.bottom.append(line) + else: + self.bottom.append(line) + templateFile.close() + + if top_add == 1: + mymsg = _("The marker '' was not in the template") + gnome.ui.GnomeErrorDialog(mymsg) + except IOError,msg: + + mymsg = _("Could not open %s\nUsing the default template") % \ + self.template + mymsg = "%s\n%s" % (mymsg,msg) + gnome.ui.GnomeWarningDialog(mymsg) + self.bottom = _bottom + self.top = _top + except: + mymsg = _("Could not open %s\nUsing the default template") % \ + self.template + gnome.ui.GnomeWarningDialog(mymsg) + self.bottom = _bottom + self.top = _top + else: + self.bottom = _bottom + self.top = _top + + def open(self,filename): + if filename[-5:] == ".html" or filename[-4:0] == ".htm": + self.filename = filename + else: + self.filename = filename + ".html" + + self.base = os.path.dirname(self.filename) + + self.f = open(self.filename,"w") + self.f.write(self.file_header) + self.f.write(self.style_declaration) + + def build_header(self): + top = string.join(self.top, "") + match = t_header_line_re.match(top) + if match: + m = match.groups() + self.file_header = '%s%s%s\n' % (m[0],m[1],m[2]) + else: + self.file_header = top + + def build_style_declaration(self): + text = ['') + self.style_declaration = string.join(text,'\n') + + def close(self): + for line in self.bottom: + self.f.write(line) + self.f.close() + + def add_photo(self,name,pos,x,y): + if no_pil: + return + + self.empty = 0 + try: + im = PIL.Image.open(name) + except: + return + + nx,ny = im.size + + scale = float(nx)/float(ny) + if scale > 1.0: + scale = 1.0/scale + act_width = float(x) + act_height = float(y * scale) + else: + act_width = float(x * scale) + act_height = float(y) + + cmtopt = float(150.0/2.54) + pixx = int(act_width*cmtopt) + pixy = int(act_height*cmtopt) + im.thumbnail((pixx,pixy)) + + imdir = self.base + os.sep + "images" + if not os.path.isdir(imdir): + try: + os.mkdir(imdir) + except: + return + + refname = "is%s" % os.path.basename(name) + try: + im.save(imdir + os.sep + refname) + except: + return + + if pos == "right": + xtra = ' align="right"' + elif pos == "left" : + xtra = ' align="left"' + else: + xtra = '' + + self.f.write('\n' % \ + (refname,pixx,pixy,xtra)) + + def start_table(self,name,style): + self.tbl = self.table_styles[style] + self.f.write('\n') + + def end_table(self): + self.f.write('
\n') + + def start_row(self): + self.col = 0 + self.f.write('\n') + + def end_row(self): + self.f.write('\n') + + def start_cell(self,style_name,span=1): + self.empty = 1 + self.f.write(' 1: + self.f.write(' colspan="' + str(span) + '"') + self.col = self.col + 1 + else: + self.f.write(' width="') + self.f.write(str(self.tbl.get_column_width(self.col))) + self.f.write('%"') + self.f.write(' class="') + self.f.write(style_name) + self.f.write('">') + self.col = self.col + 1 + + def end_cell(self): + self.f.write('\n') + + def start_paragraph(self,style_name,leader=None): + self.f.write('

') + if leader != None: + self.f.write(leader) + self.f.write(' ') + + def end_paragraph(self): + if self.empty == 1: + self.f.write(' ') + self.empty = 0 + self.f.write('

\n') + + def write_text(self,text): + if text != "": + self.empty = 0 + text = string.replace(text,'\n','
') + self.f.write(text) + +Plugins.register_text_doc(_("HTML"),HtmlDoc,1,0,1) diff --git a/src/docgen/KwordDoc.py b/src/docgen/KwordDoc.py new file mode 100644 index 000000000..3e20eb412 --- /dev/null +++ b/src/docgen/KwordDoc.py @@ -0,0 +1,441 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2000 Donald N. Allingham +# +# 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 +# + +from TextDoc import * +from latin_utf8 import latin_to_utf8 +import utils +import time +import StringIO +import os +import gzip +from TarFile import TarFile +import Plugins +import intl +_ = intl.gettext + +try: + import PIL.Image + no_pil = 0 +except: + no_pil = 1 + +def points(val): + inch = float(val)/2.54 + return (int(inch*72)) + +#------------------------------------------------------------------------ +# +# +# +#------------------------------------------------------------------------ +class KwordDoc(TextDoc): + + def open(self,filename): + self.photo_list = [] + + if filename[-4:] != ".kwd": + self.filename = filename + ".kwd" + else: + self.filename = filename + + self.f = StringIO.StringIO() + self.m = StringIO.StringIO() + + self.m.write('') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + self.m.write('\n') + + self.f.write('') + self.f.write('') + self.f.write('\n') + self.mtime = time.time() + + if self.paper.name == "A3": + self.f.write('\n') + self.f.write('' % points(self.lmargin)) + self.f.write('\n') + self.f.write('\n') + self.f.write('\n') + self.f.write('\n') + self.f.write('\n') + + def close(self): + self.f.write('\n') + for p in self.photo_list: + self.f.write('\n' % p[1]) + self.f.write('\n') + self.f.write('\n') + self.f.write('\n' % a[0]) + self.f.write('\n') + self.f.write('\n') + self.f.write('\n') + self.f.write('\n') + for name in self.style_list.keys(): + self.f.write('\n') + + self.f.write('\n') + self.f.write('\n') + for file in self.photo_list: + self.f.write('\n' % a[0]) + self.f.write('\n') + self.f.write('\n') + + tar = TarFile(self.filename) + tar.add_file("documentinfo.xml",self.mtime,self.m) + tar.add_file("maindoc.xml",self.mtime,self.f) + for file in self.photo_list: + f = open(file[0],"r") + tar.add_file(file[1],self.mtime,f) + f.close() + tar.close() + + self.f.close() + self.m.close() + + def start_page(self,orientation=None): + pass + + def end_page(self): + pass + + def start_paragraph(self,style_name,leader=None): + self.format_list = [] + self.bold_start = 0 + self.text = "" + self.style_name = style_name + self.p = self.style_list[self.style_name] + self.font = self.p.get_font() + if self.font.get_type_face() == FONT_SERIF: + self.font_face = "times" + else: + self.font_face = "helvetica" + + if leader != None: + self.text = leader + '\t' + txt = '\n' % (len(leader)+1) + txt = txt + '\n\n' % self.font_face + self.format_list.append(txt) + + self.bold_stop = len(self.text) + + def end_paragraph(self): + if self.bold_start != 0 and self.bold_stop != len(self.text): + txt = '\n\n\n' % self.font_face + self.format_list.append(txt) + + self.f.write('\n') + self.f.write('') + self.f.write(latin_to_utf8(self.text)) + self.f.write('\n') + self.f.write('\n') + for format in self.format_list: + self.f.write(format) + self.f.write('\n') + self.f.write('\n') + self.f.write('\n' % self.style_name) + + pad = points(self.p.get_padding())/2 + self.f.write('\n' % (pad,pad)) + + if self.p.get_alignment() == PARA_ALIGN_CENTER: + self.f.write('\n') + elif self.p.get_alignment() == PARA_ALIGN_JUSTIFY: + self.f.write('\n') + elif self.p.get_alignment() == PARA_ALIGN_RIGHT: + self.f.write('\n') + else: + self.f.write('\n') + + first = self.p.get_first_indent() + left = self.p.get_left_margin() + right = self.p.get_right_margin() + self.f.write('\n' % (points(left),points(right))) + + self.f.write('\n') + self.f.write('\n' % self.font_face) + self.f.write('\n' % self.font.get_size()) + self.f.write('\n' % self.font.get_color()) + if self.font.get_bold(): + self.f.write('\n') + if self.font.get_italic(): + self.f.write('\n') + if self.font.get_underline(): + self.f.write('\n') + if self.p.get_top_border(): + self.f.write('\n') + if self.p.get_bottom_border(): + self.f.write('\n') + if self.p.get_right_border(): + self.f.write('\n') + if self.p.get_left_border(): + self.f.write('\n') + self.f.write('\n') + if left != 0: + self.f.write('\n' % points(left)) + self.f.write('\n') + self.f.write('\n') + + def start_bold(self): + self.bold_start = len(self.text) + if self.bold_stop != self.bold_start: + length = self.bold_stop - self.bold_start + txt = '\n' % (self.bold_stop,length) + txt = txt + '\n\n' % self.font_face + self.format_list.append(txt) + + def end_bold(self): + self.bold_stop = len(self.text) + length = self.bold_stop - self.bold_start + txt = '\n' % (self.bold_start,length) + txt = txt + '\n\n\n' % self.font_face + self.format_list.append(txt) + + def start_table(self,name,style_name): + pass + + def end_table(self): + pass + + def start_row(self): + pass + + def end_row(self): + pass + + def start_cell(self,style_name,span=1): + pass + + def end_cell(self): + pass + + def add_photo(self,name,pos,x,y): + if no_pil: + return + + im = PIL.Image.open(name) + nx,ny = im.size + + scale = float(nx)/float(ny) + x = points(x) + y = points(y) + + if scale > 1.0: + scale = 1.0/scale + act_width = x + act_height = y * scale + else: + act_width = x * scale + act_height = y + + index = len(self.photo_list)+1 + tag = 'pictures/picture%d.jpeg' % index + self.photo_list.append((name,tag,act_width,act_height)) + txt = '\n' % len(self.text) + txt = txt + '\n' % tag + txt = txt + '\n' + + self.bold_stop = len(self.text) + self.format_list.append(txt) + + self.text = self.text + '#' + + def horizontal_line(self): + pass + + def write_text(self,text): + self.text = self.text + text + + +if __name__ == "__main__": + + paper = PaperStyle("Letter",27.94,21.59) + + styles = StyleSheet() + foo = FontStyle() + foo.set_type_face(FONT_SANS_SERIF) + foo.set_color((255,0,0)) + foo.set_size(24) + foo.set_underline(1) + foo.set_bold(1) + foo.set_italic(1) + + para = ParagraphStyle() + para.set_alignment(PARA_ALIGN_RIGHT) + para.set_font(foo) + styles.add_style("Title",para) + + foo = FontStyle() + foo.set_type_face(FONT_SERIF) + foo.set_size(12) + + para = ParagraphStyle() + para.set_font(foo) + styles.add_style("Normal",para) + + doc = KwordDoc(styles,paper,PAPER_PORTRAIT) + doc.open("/home/dona/test") + + doc.start_paragraph("Title") + doc.write_text("My Title") + doc.end_paragraph() + + doc.start_paragraph("Normal") + doc.write_text("Hello there. This is fun") + doc.end_paragraph() + + doc.start_paragraph("Normal") + doc.write_text("This is fun. ") + doc.add_photo("/home/dona/dad.jpg",2.0,2.0) + doc.write_text("So is this. ") + doc.end_paragraph() + + doc.close() + +Plugins.register_text_doc(_("KWord"),KwordDoc,0,1,1) diff --git a/src/docgen/LaTeXDoc.py b/src/docgen/LaTeXDoc.py new file mode 100644 index 000000000..a34910a53 --- /dev/null +++ b/src/docgen/LaTeXDoc.py @@ -0,0 +1,136 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2000 Donald N. Allingham +# +# 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 +# + +from TextDoc import * +from latin_utf8 import latin_to_utf8 +import Plugins +import intl +_ = intl.gettext + +#------------------------------------------------------------------------ +# +# +# +#------------------------------------------------------------------------ +class LaTeXDoc(TextDoc): + + def open(self,filename): + if filename[-4:] != ".tex": + self.filename = filename + ".tex" + else: + self.filename = filename + + self.f = open(self.filename,"w") + options = "12pt" + + if self.orientation == PAPER_LANDSCAPE: + options = options + ",landscape" + + if self.paper.name == "A4": + options = options + ",a4paper" + elif self.paper.name == "A5": + options = options + ",a5paper" + elif self.paper.name == "B5": + options = options + ",b4paper" + + self.f.write('\\documentclass[%s]{article}\n' % options) + self.f.write('\\usepackage[T1]{fontenc}\n') + self.f.write('\\usepackage[latin1]{inputenc}\n') + self.f.write('\\begin{document}\n') + self.f.write("\\title{}\n") + self.f.write("\\author{}\n") + self.in_list = 0 + + def close(self): + if self.in_list: + self.f.write('\\end{description}\n') + self.f.write('\\end{document}\n') + self.f.close() + + def start_page(self,orientation=None): + pass + + def end_page(self): + self.f.write('\\newpage') + + def start_paragraph(self,style_name,leader=None): + style = self.style_list[style_name] + self.level = style.get_header_level() + + if leader == None and self.in_list: + self.f.write('\\end{description}\n') + self.in_list = 0 + + if self.level == 1 : + self.f.write('\\section*{') + elif self.level == 2: + self.f.write('\\subsection*{') + elif self.level == 3: + self.f.write('\\subsubsection*{') + if leader != None and not self.in_list: + self.f.write('\\begin{description}\n') + self.in_list = 1 + if leader != None: + self.f.write('\\item{%s} ' % leader) + + def end_paragraph(self): + if self.level > 0: + self.f.write('}\n') + elif not self.in_list: + self.f.write('\n\\par\\noindent\n') + else: + self.f.write('\n') + + def start_bold(self): + self.f.write('\\bfseries ') + pass + + def end_bold(self): + self.f.write('\\mdseries ') + pass + + def start_table(self,name,style_name): + pass + + def end_table(self): + pass + + def start_row(self): + pass + + def end_row(self): + pass + + def start_cell(self,style_name,span=1): + pass + + def end_cell(self): + pass + + def add_photo(self,name,pos,x,y): + pass + + def horizontal_line(self): + pass + + def write_text(self,text): + self.f.write(text) + +Plugins.register_text_doc(_("LaTeX"),LaTeXDoc,0,1,0) diff --git a/src/docgen/OpenDrawDoc.py b/src/docgen/OpenDrawDoc.py new file mode 100644 index 000000000..57679afe1 --- /dev/null +++ b/src/docgen/OpenDrawDoc.py @@ -0,0 +1,449 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2000 Donald N. Allingham +# +# 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 +# + +import os +import tempfile +import string +import Plugins +import intl +_ = intl.gettext + +from TextDoc import * +from DrawDoc import * + +from latin_utf8 import latin_to_utf8 +import const + +try: + from codecs import * +except: + def EncodedFile(a,b,c): + return a + + +class OpenDrawDoc(DrawDoc): + + def __init__(self,styles,type,orientation): + DrawDoc.__init__(self,styles,type,orientation) + self.f = None + self.filename = None + self.level = 0 + self.time = "0000-00-00T00:00:00" + self.page = 0 + + def open(self,filename): + import time + + t = time.localtime(time.time()) + self.time = "%04d-%02d-%02dT%02d:%02d:%02d" % \ + (t[0],t[1],t[2],t[3],t[4],t[5]) + + if filename[-4:] != ".sxd": + self.filename = filename + ".sxd" + else: + self.filename = filename + + tempfile.tempdir = "/tmp" + self.tempdir = tempfile.mktemp() + os.mkdir(self.tempdir,0700) + os.mkdir(self.tempdir + os.sep + "Pictures") + os.mkdir(self.tempdir + os.sep + "META-INF") + + fname = self.tempdir + os.sep + "content.xml" + self.f = EncodedFile(open(fname,"wb"),'latin-1','utf-8') + + 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') + for key in self.style_list.keys(): + style = self.style_list[key] + self.f.write('\n') + self.f.write('\n') + self.f.write('\n') + self.f.write('\n') + self.f.write('\n') + + def close(self): + self.f.write('\n') + self.f.write('\n') + self.f.close() + self._write_styles_file() + self._write_manifest() + self._write_meta_file() + self._write_zip() + + def _write_zip(self): + + if os.path.isfile(self.filename): + os.unlink(self.filename) + + os.system("cd " + self.tempdir + "; " + const.zipcmd + " " \ + + self.filename + " .") + + os.unlink(self.tempdir + os.sep + "META-INF" + os.sep + "manifest.xml") + os.unlink(self.tempdir + os.sep + "content.xml") + os.unlink(self.tempdir + os.sep + "meta.xml") + os.unlink(self.tempdir + os.sep + "styles.xml") +# for image in self.image_list: +# os.unlink(self.tempdir + os.sep + "Pictures" + os.sep + image) + os.rmdir(self.tempdir + os.sep + "Pictures") + os.rmdir(self.tempdir + os.sep + "META-INF") + os.rmdir(self.tempdir) + + def _write_styles_file(self): + file = self.tempdir + os.sep + "styles.xml" + self.f = EncodedFile(open(file,"wb"),'latin-1','utf-8') + 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.write('\n') + 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') + + self.f.write('\n') + for key in self.style_list.keys(): + style = self.style_list[key] + self.f.write('\n') + self.f.write('\n') + self.f.write('\n') + + # Current no leading number format for headers + + self.f.write('\n') + self.f.write('\n') + self.f.write('\n') + self.f.write('\n' % self.rmargin) + 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.write('\n') + self.f.write('\n') + self.f.write('\n') + self.f.close() + + def start_paragraph(self,style_name): + self.f.write('' % style_name) + + def end_paragraph(self): + self.f.write('\n') + + def write_text(self,text): + text = string.replace(text,'\t','') + text = string.replace(text,'\n','') + self.f.write(latin_to_utf8(text)) + + def _write_manifest(self): + file = self.tempdir + os.sep + "META-INF" + os.sep + "manifest.xml" + self.f = EncodedFile(open(file,"wb"),'latin-1','utf-8') + self.f.write('\n') + self.f.write('') + self.f.write('') + self.f.write('') + self.f.write('') + self.f.write('') + self.f.write('') + #self.f.write('') + self.f.write('\n') + self.f.close() + + def _write_meta_file(self): + file = self.tempdir + os.sep + "meta.xml" + name = latin_to_utf8(self.name) + self.f = EncodedFile(open(file,"wb"),'latin-1','utf-8') + self.f.write('\n') + self.f.write('\n'); + self.f.write('\n') + self.f.write('') + self.f.write(const.progName + ' ' + const.version) + self.f.write('\n') + self.f.write('') + self.f.write(name) + self.f.write('\n') + self.f.write('') + self.f.write(self.time) + self.f.write('\n') + self.f.write('') + self.f.write(name) + self.f.write('\n') + self.f.write('') + self.f.write(self.time) + self.f.write('\n') + self.f.write('0-00-00T00:00:00\n') + self.f.write('en-US\n') + self.f.write('1\n') + self.f.write('PT0S\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 start_page(self,orientation=None): + self.page = self.page + 1 + self.f.write('\n') + + def end_page(self): + self.f.write('\n') + + def draw_line(self,style,x1,y1,x2,y2): + self.f.write('\n' % y2) + + def draw_box(self,style,text,x,y): + box_style = self.draw_styles[style] + para_name = box_style.get_paragraph_style() + + self.f.write('') + text = latin_to_utf8(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') + +Plugins.register_draw_doc(_("OpenOffice/StarOffice 6"),OpenDrawDoc); diff --git a/src/docgen/OpenOfficeDoc.py b/src/docgen/OpenOfficeDoc.py new file mode 100644 index 000000000..dd010d155 --- /dev/null +++ b/src/docgen/OpenOfficeDoc.py @@ -0,0 +1,579 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2000 Donald N. Allingham +# +# 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 +# + +import os +import tempfile +import string + +from TextDoc import * +from latin_utf8 import latin_to_utf8 +import const +import utils +import Plugins +import intl +_ = intl.gettext + +try: + import PIL.Image + no_pil = 0 +except: + no_pil = 1 + +try: + from codecs import * +except: + def EncodedFile(a,b,c): + return a + +class OpenOfficeDoc(TextDoc): + + def __init__(self,styles,type,template,orientation): + TextDoc.__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 + + def open(self,filename): + import time + + t = time.localtime(time.time()) + self.time = "%04d-%02d-%02dT%02d:%02d:%02d" % \ + (t[0],t[1],t[2],t[3],t[4],t[5]) + + if filename[-4:] != ".sxw": + self.filename = filename + ".sxw" + else: + self.filename = filename + + tempfile.tempdir = "/tmp" + self.tempdir = tempfile.mktemp() + os.mkdir(self.tempdir,0700) + os.mkdir(self.tempdir + os.sep + "Pictures") + os.mkdir(self.tempdir + os.sep + "META-INF") + + fname = self.tempdir + os.sep + "content.xml" + self.f = EncodedFile(open(fname,"wb"),'latin-1','utf-8') + + 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') + for style_name in self.style_list.keys(): + style = self.style_list[style_name] + self.f.write('\n\n') + self.f.write('\n') + for style_name in self.table_styles.keys(): + style = self.table_styles[style_name] + self.f.write('\n') + table_width = float(self.get_usable_width()) + table_width_str = "%.4f" % table_width + self.f.write('\n') + self.f.write('\n') + for col in range(0,style.get_columns()): + self.f.write('') + width = table_width * float(style.get_column_width(col)/100.0) + width_str = "%.4f" % width + self.f.write('' % width_str) + self.f.write('\n') + for cell in self.cell_styles.keys(): + cell_style = self.cell_styles[cell] + self.f.write('\n') + self.f.write('\n') + self.f.write('\n') + + self.f.write('\n') + self.f.write('\n') + self.f.write('\n') + + #Begin photo style + self.f.write('') + self.f.write('') + self.f.write('\n') + + self.f.write('') + self.f.write('') + self.f.write('\n') + + self.f.write('') + self.f.write('') + self.f.write('\n') + + self.f.write('') + self.f.write('') + self.f.write('\n') + + #end of Photo style edits + + self.f.write('\n') + self.f.write('\n') + + def close(self): + self.f.write('\n') + self.f.write('\n') + self.f.close() + self._write_styles_file() + self._write_manifest() + self._write_meta_file() + self._write_photos() + self._write_zip() + + def add_photo(self,name,pos,x_cm,y_cm): + import gtk + import GdkImlib + + image = GdkImlib.Image(name) + scale = float(image.rgb_width)/float(image.rgb_height) + act_width = int(((x_cm * scale)*2.54)*72) + act_height = int(((y_cm * scale)*2.54)*72) + + self.photo_list.append((name,act_width,act_height)) + + base = os.path.basename(name) + tag = string.replace(base,'.','_') + + if pos == "left": + self.f.write('\n') + + def start_table(self,name,style_name): + self.f.write('\n') + table = self.table_styles[style_name] + for col in range(0,table.get_columns()): + self.f.write('\n') + + def end_table(self): + self.f.write('\n') + + def start_row(self): + self.f.write('\n') + + def end_row(self): + self.f.write('\n') + + def start_cell(self,style_name,span=1): + self.span = span + self.f.write(' 1: + self.f.write(' table:number-columns-spanned="' + str(span) + '">\n') + else: + self.f.write('>\n') + + def end_cell(self): + self.f.write('\n') + for col in range(1,self.span): + self.f.write('\n') + + def start_bold(self): + self.f.write('') + + def end_bold(self): + self.f.write('') + + def _write_zip(self): + + if os.path.isfile(self.filename): + os.unlink(self.filename) + + os.system("cd " + self.tempdir + "; " + const.zipcmd + " " \ + + self.filename + " .") + + os.unlink(self.tempdir + os.sep + "META-INF" + os.sep + "manifest.xml") + os.unlink(self.tempdir + os.sep + "content.xml") + os.unlink(self.tempdir + os.sep + "meta.xml") + os.unlink(self.tempdir + os.sep + "styles.xml") + for image in self.photo_list: + base = os.path.basename(image[0]) + os.unlink(self.tempdir + os.sep + "Pictures" + os.sep + base) + os.rmdir(self.tempdir + os.sep + "Pictures") + os.rmdir(self.tempdir + os.sep + "META-INF") + os.rmdir(self.tempdir) + + def _write_styles_file(self): + file = self.tempdir + os.sep + "styles.xml" + + self.f = EncodedFile(open(file,"wb"),'latin-1','utf-8') + + 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.write('\n') + self.f.write('\n') + + for key in self.style_list.keys(): + style = self.style_list[key] + self.f.write('\n') + self.f.write('\n') + self.f.write('\n') + + # Current no leading number format for headers + + 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.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.write('\n') + self.f.write('\n') + self.f.close() + + def page_break(self): + 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 + name = "NL%s" % style_name + else: + name = style_name + if self.level == 0: + self.f.write('' % name) + else: + self.f.write('') + if leader != None: + self.f.write(latin_to_utf8(leader)) + self.f.write('') + + def end_paragraph(self): + if self.level == 0: + self.f.write('\n') + else: + self.f.write('\n') + + def write_text(self,text): + text = string.replace(text,'\n','') + self.f.write(latin_to_utf8(text)) + + def _write_photos(self): + + for file_tuple in self.photo_list: + file = file_tuple[0] + width = file_tuple[1] + height = file_tuple[2] + base = os.path.basename(file) + image_name = self.tempdir + os.sep + "Pictures" + os.sep + base + if no_pil: + cmd = "%s -geometry %dx%d '%s' '%s'" % (const.convert,width,height,file,image_name) + os.system(cmd) + else: + im = PIL.Image.open(file) + im.thumbnail((width,height)) + im.save(image_name,"JPEG") + + def _write_manifest(self): + file = self.tempdir + os.sep + "META-INF" + os.sep + "manifest.xml" + self.f = EncodedFile(open(file,"wb"),'latin-1','utf-8') + self.f.write('\n') + self.f.write('') + self.f.write('') + for image in self.photo_list: + i = image[0] + base = os.path.basename(i) + self.f.write('') + self.f.write('') + self.f.write('') + self.f.write('') + self.f.write('') + self.f.write('\n') + self.f.close() + + def _write_meta_file(self): + file = self.tempdir + os.sep + "meta.xml" + name = latin_to_utf8(self.name) + self.f = EncodedFile(open(file,"wb"),'latin-1','utf-8') + self.f.write('\n') + self.f.write('\n'); + self.f.write('\n') + self.f.write('') + self.f.write(const.progName + ' ' + const.version) + self.f.write('\n') + self.f.write('') + self.f.write(name) + self.f.write('\n') + self.f.write('') + self.f.write(self.time) + self.f.write('\n') + self.f.write('') + self.f.write(name) + self.f.write('\n') + self.f.write('') + self.f.write(self.time) + self.f.write('\n') + self.f.write('0-00-00T00:00:00\n') + self.f.write('en-US\n') + self.f.write('1\n') + self.f.write('PT0S\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() + +Plugins.register_text_doc(_("OpenOffice/StarOffice 6"),OpenOfficeDoc,1,1,1) diff --git a/src/docgen/OpenSpreadSheet.py b/src/docgen/OpenSpreadSheet.py new file mode 100644 index 000000000..427f2e279 --- /dev/null +++ b/src/docgen/OpenSpreadSheet.py @@ -0,0 +1,457 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2000 Donald N. Allingham +# +# 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 +# + +import os +import tempfile +import string + +from TextDoc import * +from SpreadSheetDoc import * + +from latin_utf8 import latin_to_utf8 +import const + +class OpenSpreadSheet(SpreadSheetDoc): + + def __init__(self,type,orientation): + SpreadSheetDoc.__init__(self,type,orientation) + self.f = None + self.filename = None + self.level = 0 + self.time = "0000-00-00T00:00:00" + + def open(self,filename): + import time + + t = time.localtime(time.time()) + self.time = "%04d-%02d-%02dT%02d:%02d:%02d" % \ + (t[0],t[1],t[2],t[3],t[4],t[5]) + + if filename[-4:] != ".sxc": + self.filename = filename + ".sxc" + else: + self.filename = filename + + tempfile.tempdir = "/tmp" + self.tempdir = tempfile.mktemp() + os.mkdir(self.tempdir,0700) + os.mkdir(self.tempdir + os.sep + "Pictures") + os.mkdir(self.tempdir + os.sep + "META-INF") + + self.f = open(self.tempdir + os.sep + "content.xml","w") + 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') + for key in self.table_styles.keys(): + table = self.table_styles[key] + self.f.write('\n') + self.f.write('\n') + self.f.write('\n') + for index in range(0,table.get_columns()): + self.f.write('\n') + self.f.write('\n' % table.get_column_width(index)) + self.f.write('\n') + + self.f.write('\n') + self.f.write('\n') + self.f.write('\n') + + for key in self.style_list.keys(): + style = self.style_list[key] + font = style.get_font() + self.f.write('\n') + self.f.write('\n') + else: + self.f.write('fo:font-weight="normal"/>\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') + + def close(self): + self.f.write('\n') + self.f.write('\n') + self.f.close() + self._write_styles_file() + self._write_manifest() + self._write_meta_file() + self._write_zip() + + def start_row(self): + self.f.write('\n') + + def end_row(self): + self.f.write('\n') + + def start_cell(self,style_name,span=1): + self.content = 0 + self.span = span + self.f.write(' 1: + self.f.write(' table:number-columns-spanned="' + str(span) + '">\n') + else: + self.f.write('>\n') + + def end_cell(self): + if self.content == 0: + self.f.write('\n') + else: + self.f.write('\n') + self.f.write('\n') + for col in range(1,self.span): + self.f.write('\n') + + def _write_zip(self): + + if os.path.isfile(self.filename): + os.unlink(self.filename) + + os.system("cd " + self.tempdir + "; " + const.zipcmd + " " \ + + self.filename + " .") + + os.unlink(self.tempdir + os.sep + "META-INF" + os.sep + "manifest.xml") + os.unlink(self.tempdir + os.sep + "content.xml") + os.unlink(self.tempdir + os.sep + "meta.xml") + os.unlink(self.tempdir + os.sep + "styles.xml") +# for image in self.image_list: +# os.unlink(self.tempdir + os.sep + "Pictures" + os.sep + image) + os.rmdir(self.tempdir + os.sep + "Pictures") + os.rmdir(self.tempdir + os.sep + "META-INF") + os.rmdir(self.tempdir) + + def _write_styles_file(self): + file = self.tempdir + os.sep + "styles.xml" + self.f = open(file,"w") + 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.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.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.write('???\n') + self.f.write('\n') + self.f.write('\n') + self.f.write('Page 1\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('(???)\n') + self.f.write('\n') + self.f.write('\n') + self.f.write('05/16/2001, ') + self.f.write('10:53:17\n') + self.f.write('\n') + self.f.write('\n') + self.f.write('\n') + self.f.write('Page 1 / ') + self.f.write('99\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 start_page(self,name,style_name): + table = self.table_styles[style_name] + self.f.write('\n') + for col in range(0,table.get_columns()): + self.f.write('\n') + + def end_page(self): + self.f.write('\n') + + def write_text(self,text): + if text == "": + return + if self.content == 0: + self.f.write('') + self.content = 1 + text = string.replace(text,'\t','') + text = string.replace(text,'\n','') + self.f.write(latin_to_utf8(text)) + + def _write_manifest(self): + file = self.tempdir + os.sep + "META-INF" + os.sep + "manifest.xml" + self.f = open(file,"w") + self.f.write('\n') + self.f.write('') + self.f.write('') + self.f.write('') + self.f.write('') + self.f.write('') + self.f.write('') + #self.f.write('') + self.f.write('\n') + self.f.close() + + def _write_meta_file(self): + file = self.tempdir + os.sep + "meta.xml" + name = latin_to_utf8(self.name) + self.f = open(file,"w") + self.f.write('\n') + self.f.write('\n'); + self.f.write('\n') + self.f.write('') + self.f.write(const.progName + ' ' + const.version) + self.f.write('\n') + self.f.write('') + self.f.write(name) + self.f.write('\n') + self.f.write('') + self.f.write(self.time) + self.f.write('\n') + self.f.write('') + self.f.write(name) + self.f.write('\n') + self.f.write('') + self.f.write(self.time) + self.f.write('\n') + self.f.write('0-00-00T00:00:00\n') + self.f.write('en-US\n') + self.f.write('1\n') + self.f.write('PT0S\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() + +if __name__ == "__main__": + + doc = OpenSpreadSheet(PaperStyle("junk",21.59,27),PAPER_PORTRAIT) + + t = TableStyle() + t.set_columns(3) + t.set_column_width(0,4) + t.set_column_width(1,2) + t.set_column_width(2,1) + doc.add_table_style("mytblstyle",t) + + f = FontStyle() + f.set_type_face(FONT_SANS_SERIF) + f.set_size(16) + f.set_bold(1) + p = ParagraphStyle() + p.set_font(f) + p.set_background_color((0xcc,0xff,0xff)) + p.set_padding(0.5) + doc.add_style("p1",p) + + doc.open("/home/dona/test") + doc.start_page("Page 1","mytblstyle") + doc.start_row() + doc.start_cell("p1") + doc.write_text("Hello") + doc.end_cell() + doc.end_row() + doc.end_page() + doc.close() diff --git a/src/docgen/PSDrawDoc.py b/src/docgen/PSDrawDoc.py new file mode 100644 index 000000000..28b79e181 --- /dev/null +++ b/src/docgen/PSDrawDoc.py @@ -0,0 +1,168 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2000 Donald N. Allingham +# +# 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 +# + +import os +import tempfile +import string +import Plugins +import intl +_ = intl.gettext + +from TextDoc import * +from DrawDoc import * + + +class PSDrawDoc(DrawDoc): + + def __init__(self,styles,type,orientation): + DrawDoc.__init__(self,styles,type,orientation) + self.f = None + self.filename = None + self.level = 0 + self.time = "0000-00-00T00:00:00" + self.page = 0 + + def translate(self,x,y): + return (x,self.height-y) + + def fontdef(self,para): + font = para.get_font() + if font.get_type_face() == FONT_SERIF: + if font.get_bold(): + if font.get_italic(): + font_name = "/Times-BoldItalic" + else: + font_name = "/Times-Bold" + else: + if font.get_italic(): + font_name = "/Times-Italic" + else: + font_name = "/Times-Roman" + else: + if font.get_bold(): + if font.get_italic(): + font_name = "/Helvetica-BoldOblique" + else: + font_name = "/Helvetica-Bold" + else: + if font.get_italic(): + font_name = "/Helvetica-Oblique" + else: + font_name = "/Helvetica" + + return "%s findfont %d scalefont setfont\n" % (font_name,font.get_size()) + + def open(self,filename): + if filename[-4:] != ".ps": + self.filename = filename + ".ps" + else: + self.filename = filename + self.f = open(filename,"w") + self.f.write('%!PS-Adobe-3.0\n') + self.f.write('%%LanguageLevel: 2\n') + self.f.write('%%Pages: (atend)\n') + self.f.write('%%PageOrder: Ascend\n') + self.f.write('%%EndComments\n') + self.f.write('/cm { 28.34 mul } def\n') + + def close(self): + self.f.write('%%Trailer\n') + self.f.write('%%Pages: ') + self.f.write('%d\n' % self.page) + self.f.write('%%EOF\n') + self.f.close() + + def start_paragraph(self,style_name): + pass + + def end_paragraph(self): + pass + + def write_text(self,text): + pass + + def start_page(self,orientation=None): + self.page = self.page + 1 + self.f.write("%%Page:") + self.f.write("%d %d\n" % (self.page,self.page)) + + def end_page(self): + self.f.write('showpage\n') + self.f.write('%%PageTrailer\n') + + def draw_line(self,style,x1,y1,x2,y2): + self.f.write('gsave\n') + self.f.write('newpath\n') + self.f.write('%f cm %f cm moveto\n' % self.translate(x1,y1)) + self.f.write('%f cm %f cm lineto\n' % self.translate(x2,y2)) + self.f.write('1 setlinewidth\n') + self.f.write('2 setlinecap\n') + self.f.write('stroke\n') + self.f.write('grestore\n') + + def draw_box(self,style,text,x,y): + box_style = self.draw_styles[style] + para_name = box_style.get_paragraph_style() + p = self.style_list[para_name] + + bh = box_style.get_height() + bw = box_style.get_width() + self.f.write('gsave\n') + self.f.write('newpath\n') + self.f.write('%f cm %f cm moveto\n' % self.translate(x+0.15,y+0.15)) + self.f.write('0 -%f cm rlineto\n' % bh) + self.f.write('%f cm 0 rlineto\n' % bw) + self.f.write('0 %f cm rlineto\n' % bh) + self.f.write('closepath\n') + self.f.write('.5 setgray\n') + self.f.write('fill\n') + self.f.write('newpath\n') + self.f.write('%f cm %f cm moveto\n' % self.translate(x,y)) + self.f.write('0 -%f cm rlineto\n' % bh) + self.f.write('%f cm 0 rlineto\n' % bw) + self.f.write('0 %f cm rlineto\n' % bh) + self.f.write('closepath\n') + self.f.write('1 setgray\n') + self.f.write('fill\n') + self.f.write('newpath\n') + self.f.write('%f cm %f cm moveto\n' % self.translate(x,y)) + self.f.write('0 -%f cm rlineto\n' % bh) + self.f.write('%f cm 0 rlineto\n' % bw) + self.f.write('0 %f cm rlineto\n' % bh) + self.f.write('closepath\n') + self.f.write('0 setgray\n') + self.f.write('1 setlinewidth\n') + self.f.write('stroke\n') + if text != "": + self.f.write(self.fontdef(p)) + lines = string.split(text,'\n') + nlines = len(lines) + mar = 10/28.35 + f_in_cm = p.get_font().get_size()/28.35 + fs = f_in_cm * 1.2 + center = y + (bh + fs)/2.0 + (fs*0.2) + ystart = center - (fs/2.0) * nlines + for i in range(nlines): + ypos = ystart + (i * fs) + self.f.write('%f cm %f cm moveto\n' % self.translate(x+mar,ypos)) + self.f.write("(%s) show\n" % lines[i]) + self.f.write('grestore\n') + +Plugins.register_draw_doc(_("PostScript"),PSDrawDoc); diff --git a/src/docgen/PdfDoc.py b/src/docgen/PdfDoc.py new file mode 100644 index 000000000..bde2e4733 --- /dev/null +++ b/src/docgen/PdfDoc.py @@ -0,0 +1,284 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2000 Donald N. Allingham +# +# 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 +# + +from TextDoc import * +import Plugins +import intl +_ = intl.gettext + +import reportlab.platypus.tables +from reportlab.platypus import * +from reportlab.lib.units import cm +from reportlab.lib.colors import Color +from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY +import reportlab.lib.styles + +from latin_utf8 import latin_to_utf8 + +try: + import PIL.Image + no_pil = 0 +except: + no_pil = 1 + +#------------------------------------------------------------------------ +# +# +# +#------------------------------------------------------------------------ +class GrampsDocTemplate(BaseDocTemplate): + + def build(self,flowables): + self._calc() #in case we changed margins sizes etc + BaseDocTemplate.build(self,flowables) + +#------------------------------------------------------------------------ +# +# +# +#------------------------------------------------------------------------ +def make_color(color): + return Color(float(color[0])/255.0, float(color[1])/255.0, + float(color[2])/255.0) + +#------------------------------------------------------------------------ +# +# +# +#------------------------------------------------------------------------ +class PdfDoc(TextDoc): + + def open(self,filename): + if filename[-4:] != ".pdf": + self.filename = filename + ".pdf" + else: + self.filename = filename + + self.pagesize = (self.width*cm,self.height*cm) + + self.doc = GrampsDocTemplate(self.filename, + pagesize=self.pagesize, + allowSplitting=1, + _pageBreakQuick=0, + leftMargin=self.lmargin*cm, + rightMargin=self.rmargin*cm, + topMargin=self.tmargin*cm, + bottomMargin=self.bmargin*cm) + frameT = Frame(0,0,self.width*cm,self.height*cm, + self.lmargin*cm, self.bmargin*cm, \ + self.rmargin*cm,self.tmargin*cm,\ + id='normal') + ptemp = PageTemplate(frames=frameT,pagesize=self.pagesize) + self.doc.addPageTemplates([ptemp]) + + self.pdfstyles = {} + + for style_name in self.style_list.keys(): + style = self.style_list[style_name] + font = style.get_font() + + pdf_style = reportlab.lib.styles.ParagraphStyle(name=style_name) + pdf_style.fontSize = font.get_size() + pdf_style.bulletFontSize = font.get_size() + + if font.get_type_face() == FONT_SERIF: + if font.get_bold(): + if font.get_italic(): + pdf_style.fontName = "Times-BoldItalic" + else: + pdf_style.fontName = "Times-Bold" + else: + if font.get_italic(): + pdf_style.fontName = "Times-Italic" + else: + pdf_style.fontName = "Times-Roman" + else: + if font.get_bold(): + if font.get_italic(): + pdf_style.fontName = "Helvetica-BoldOblique" + else: + pdf_style.fontName = "Helvetica-Bold" + else: + if font.get_italic(): + pdf_style.fontName = "Helvetica-Oblique" + else: + pdf_style.fontName = "Helvetica" + pdf_style.bulletFontName = pdf_style.fontName + + + right = style.get_right_margin()*cm + left = style.get_left_margin()*cm + first = left + style.get_first_indent()*cm + + pdf_style.rightIndent = right + pdf_style.leftIndent = left + pdf_style.firstLineIndent = first + pdf_style.bulletIndent = first + + align = style.get_alignment() + if align == PARA_ALIGN_RIGHT: + pdf_style.alignment = TA_RIGHT + elif align == PARA_ALIGN_LEFT: + pdf_style.alignment = TA_LEFT + elif align == PARA_ALIGN_CENTER: + pdf_style.alignment = TA_CENTER + else: + pdf_style.alignment = TA_JUSTIFY + pdf_style.spaceBefore = style.get_padding() + pdf_style.spaceAfter = style.get_padding() + pdf_style.textColor = make_color(font.get_color()) + self.pdfstyles[style_name] = pdf_style + + self.story = [] + self.in_table = 0 + + def close(self): + self.doc.build(self.story) + + def end_page(self): + self.story.append(PageBreak()) + + def start_paragraph(self,style_name,leader=None): + self.current_para = self.pdfstyles[style_name] + self.my_para = self.style_list[style_name] + if leader==None: + self.text = '' + else: + self.text = '%s' % leader + self.image = 0 + + def end_paragraph(self): + if self.in_table == 0 and self.image == 0: + self.story.append(Paragraph(self.text,self.current_para)) + self.story.append(Spacer(1,0.5*cm)) + else: + self.image = 0 + + def start_bold(self): + self.text = self.text + '' + + def end_bold(self): + self.text = self.text + '' + + def start_table(self,name,style_name): + self.in_table = 1 + self.cur_table = self.table_styles[style_name] + self.row = -1 + self.col = 0 + self.cur_row = [] + self.table_data = [] + + self.tblstyle = [] + self.cur_table_cols = [] + width = float(self.cur_table.get_width()/100.0) * self.get_usable_width() + for val in range(self.cur_table.get_columns()): + percent = float(self.cur_table.get_column_width(val))/100.0 + self.cur_table_cols.append(int(width * percent * cm)) + + def end_table(self): + ts = reportlab.platypus.tables.TableStyle(self.tblstyle) + tbl = reportlab.platypus.tables.Table(data=self.table_data, + colWidths=self.cur_table_cols, + style=ts) + self.story.append(tbl) + self.in_table = 0 + + def start_row(self): + self.row = self.row + 1 + self.col = 0 + self.cur_row = [] + + def end_row(self): + self.table_data.append(self.cur_row) + + def start_cell(self,style_name,span=1): + self.span = span + self.my_table_style = self.cell_styles[style_name] + pass + + def end_cell(self): + if self.span == 1: +# self.cur_row.append(self.text) + self.cur_row.append(Paragraph(self.text,self.current_para)) + else: + self.cur_row.append(self.text) + for val in range(1,self.span): + self.cur_row.append("") + + p = self.my_para + f = p.get_font() + if f.get_type_face() == FONT_SANS_SERIF: + if f.get_bold(): + fn = 'Helvetica-Bold' + else: + fn = 'Helvetica' + else: + if f.get_bold(): + fn = 'Times-Bold' + else: + fn = 'Times-Roman' + + black = Color(0,0,0) + + for inc in range(self.col,self.col+self.span): + loc = (inc,self.row) + self.tblstyle.append(('FONT', loc, loc, fn, f.get_size())) + if self.span == 1 or inc == self.col + self.span - 1: + if self.my_table_style.get_right_border(): + self.tblstyle.append('LINEAFTER', loc, loc, 1, black) + if self.span == 1 or inc == self.col: + if self.my_table_style.get_left_border(): + self.tblstyle.append('LINEBEFORE', loc, loc, 1, black) + if self.my_table_style.get_top_border(): + self.tblstyle.append('LINEABOVE', loc, loc, 1, black) + if self.my_table_style.get_bottom_border(): + self.tblstyle.append('LINEBELOW', loc, loc, 1, black) + if p.get_alignment() == PARA_ALIGN_LEFT: + self.tblstyle.append('ALIGN', loc, loc, 'LEFT') + elif p.get_alignment() == PARA_ALIGN_RIGHT: + self.tblstyle.append('ALIGN', loc, loc, 'RIGHT') + else: + self.tblstyle.append('ALIGN', loc, loc, 'CENTER') + self.tblstyle.append('VALIGN', loc, loc, 'TOP') + + self.col = self.col + self.span + + def add_photo(self,name,pos,x,y): + if no_pil == 0: + im = PIL.Image.open(name) + + nx,ny = im.size + scale = float(nx)/float(ny) + if scale > 1.0: + scale = 1.0/scale + act_width = x + act_height = y * scale + else: + act_width = x * scale + act_height = y + + self.story.append(Image(name,act_width*cm,act_height*cm)) + self.story.append(Spacer(1,0.5*cm)) + self.image = 1 + + def write_text(self,text): + self.text = self.text + text + +Plugins.register_text_doc(_("PDF"),PdfDoc,1,1,1) diff --git a/src/docgen/PdfDrawDoc.py b/src/docgen/PdfDrawDoc.py new file mode 100644 index 000000000..7b4189177 --- /dev/null +++ b/src/docgen/PdfDrawDoc.py @@ -0,0 +1,185 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2000 Donald N. Allingham +# +# 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 +# + +import os +import string + +from TextDoc import * +from DrawDoc import * +import Plugins +import intl +_ = intl.gettext + +from reportlab.pdfgen import canvas +from reportlab.lib.units import cm +from reportlab.lib.colors import Color + +def make_color(color): + return Color(float(color[0])/255.0, float(color[1])/255.0, + float(color[2])/255.0) + +class PdfDrawDoc(DrawDoc): + + def __init__(self,styles,type,orientation): + DrawDoc.__init__(self,styles,type,orientation) + self.f = None + self.filename = None + self.level = 0 + self.time = "0000-00-00T00:00:00" + self.page = 0 + + def open(self,filename): + + if filename[-4:] != ".pdf": + self.filename = filename + ".pdf" + else: + self.filename = filename + self.f = canvas.Canvas(self.filename,(self.width*cm,self.height*cm),0) + if self.name: + self.f.setAuthor(self.name) + + def close(self): + self.f.save() + + def start_paragraph(self,style_name): + pass + + def end_paragraph(self): + pass + + def write_text(self,text): + pass + + def start_page(self,orientation=None): + pass + + def end_page(self): + self.f.showPage() + + def draw_line(self,style,x1,y1,x2,y2): + self.f.line(x1*cm,y1*cm,x2*cm,y2*cm) + + def draw_box(self,style,text,x,y): + box_style = self.draw_styles[style] + para_name = box_style.get_paragraph_style() + p = self.style_list[para_name] + + w = box_style.get_width()*cm + h = box_style.get_height()*cm + + if box_style.get_shadow(): + self.f.setFillColorRGB(0.5,0.5,0.5) + self.f.rect((x+0.3)*cm,(y+0.3)*cm,w,h,fill=1,stroke=0) + + font = p.get_font() + + self.f.setStrokeColor(make_color(font.get_color())) + self.f.setFillColor(make_color(box_style.get_color())) + + self.f.rect(x*cm,y*cm,w,h,fill=1) + + if text != "": + lines = string.split(text,'\n') + self.center_print(lines,font,x*cm,y*cm,w,h) + + def write_at(self,style,text,x,y): + p = self.style_list[style] + font = p.get_font() + + self.f.setStrokeColor(make_color(font.get_color())) + + self.left_print(text,font,x*cm,y*cm) + + def center_print(self,lines,font,x,y,w,h): + l = len(lines) + size = font.get_size() + start_y = (y + h/2.0 + l/2.0 + l) - ((l*size) + ((l-1)*0.2))/2.0 + start_x = (x + w/2.0) + + self.f.saveState() + self.f.setFillColor(make_color(font.get_color())) + if font.get_type_face() == FONT_SANS_SERIF: + if font.get_bold(): + self.f.setFont("Helvetica-Bold",font.get_size()) + else: + self.f.setFont("Helvetica",font.get_size()) + else: + if font.get_bold(): + self.f.setFont("Times-Bold",font.get_size()) + else: + self.f.setFont("Times-Roman",font.get_size()) + + for text in lines: + self.f.drawCentredString(start_x,start_y,text) + start_y = start_y + size*1.2 + start_y = start_y + size*1.2 + + self.f.restoreState() + + def left_print(self,text,font,x,y): + size = font.get_size() + start_y = y + start_x = x + + self.f.saveState() + self.f.setFillColor(make_color(font.get_color())) + if font.get_type_face() == FONT_SANS_SERIF: + if font.get_bold(): + self.f.setFont("Helvetica-Bold",font.get_size()) + else: + self.f.setFont("Helvetica",font.get_size()) + else: + if font.get_bold(): + self.f.setFont("Times-Bold",font.get_size()) + else: + self.f.setFont("Times-Roman",font.get_size()) + + self.f.drawString(start_x,start_y,text) + self.f.restoreState() + +if __name__ == "__main__": + + + + s = PaperStyle("Junk",27.94,21.59) + x = PdfDrawDoc(s,PAPER_PORTRAIT) + f = FontStyle() + f.set_type_face(FONT_SANS_SERIF) + f.set_size(14) + p = ParagraphStyle() + p.set_font(f) + x.add_paragraph_style("mytest",p) + + g = GraphicsStyle() + g.set_width(4) + g.set_height(2) + + g.set_color((0xff,0xcc,0xff)) + g.set_paragraph_style("mytest") + g.set_shadow(1) + x.add_draw_style("mybox",g) + + x.open("test") + x.start_page() + x.draw_box("mybox","Hello\nThis is Fun",4,4) + x.end_page() + x.close() + +Plugins.register_draw_doc(_("PDF"),PdfDrawDoc); diff --git a/src/docgen/RTFDoc.py b/src/docgen/RTFDoc.py new file mode 100644 index 000000000..90c0d2ff8 --- /dev/null +++ b/src/docgen/RTFDoc.py @@ -0,0 +1,525 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2000 Donald N. Allingham +# +# 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 +# + +#------------------------------------------------------------------------ +# +# Load the base TextDoc class +# +#------------------------------------------------------------------------ +from TextDoc import * +import Plugins +import intl +_ = intl.gettext + +#------------------------------------------------------------------------ +# +# Attempt to load the Python Imaging Library for the handling of photos. +# +#------------------------------------------------------------------------ +try: + import PIL.Image + no_pil = 0 +except: + no_pil = 1 + +#------------------------------------------------------------------------ +# +# RTF uses a unit called "twips" for its measurements. According to the +# RTF specification, 1 point is 20 twips. This routines converts +# centimeters to twips +# +# 2.54 cm/inch 72pts/inch, 20twips/pt +# +#------------------------------------------------------------------------ +def twips(cm): + return int(((cm/2.54)*72)+0.5)*20 + +#------------------------------------------------------------------------ +# +# Rich Text Format Document interface. The current inteface does not +# use style sheets. Instead it writes raw formatting. +# +#------------------------------------------------------------------------ +class RTFDoc(TextDoc): + + #-------------------------------------------------------------------- + # + # Opens the file, and writes the header. Builds the color and font + # tables. Fonts are chosen using the MS TrueType fonts, since it + # is assumed that if you are generating RTF, you are probably + # targeting Word. This generator assumes a Western Europe character + # set. + # + #-------------------------------------------------------------------- + def open(self,filename): + if filename[-4:] != ".rtf": + self.filename = filename + ".rtf" + else: + self.filename = filename + + self.f = open(self.filename,"w") + self.f.write('{\\rtf1\\ansi\\ansicpg1252\\deff0\n') + self.f.write('{\\fonttbl\n') + self.f.write('{\\f0\\froman\\fcharset0\\fprq0 Times New Roman;}\n') + self.f.write('{\\f1\\fswiss\\fcharset0\\fprq0 Arial;}}\n') + self.f.write('{\colortbl\n') + self.color_map = {} + index = 1 + self.color_map[(0,0,0)] = 0 + self.f.write('\\red0\\green0\\blue0;') + for style_name in self.style_list.keys(): + style = self.style_list[style_name] + fgcolor = style.get_font().get_color() + bgcolor = style.get_background_color() + if not self.color_map.has_key(fgcolor): + self.color_map[fgcolor] = index + self.f.write('\\red%d\\green%d\\blue%d;' % fgcolor) + index = index + 1 + if not self.color_map.has_key(bgcolor): + self.f.write('\\red%d\\green%d\\blue%d;' % bgcolor) + self.color_map[bgcolor] = index + index = index + 1 + self.f.write('}\n') + self.f.write('\\kerning0\\cf0\\viewkind1') + self.f.write('\\paperw%d' % twips(self.width)) + self.f.write('\\paperh%d' % twips(self.height)) + self.f.write('\\margl%d' % twips(self.lmargin)) + self.f.write('\\margr%d' % twips(self.rmargin)) + self.f.write('\\margt%d' % twips(self.tmargin)) + self.f.write('\\margb%d' % twips(self.bmargin)) + self.f.write('\\widowctl\n') + self.in_table = 0 + self.text = "" + + #-------------------------------------------------------------------- + # + # Write the closing brace, and close the file. + # + #-------------------------------------------------------------------- + def close(self): + self.f.write('}\n') + self.f.close() + + #-------------------------------------------------------------------- + # + # Force a section page break + # + #-------------------------------------------------------------------- + def end_page(self): + self.f.write('\\sbkpage\n') + + #-------------------------------------------------------------------- + # + # Starts a paragraph. Instead of using a style sheet, generate the + # the style for each paragraph on the fly. Not the ideal, but it + # does work. + # + #-------------------------------------------------------------------- + def start_paragraph(self,style_name,leader=None): + self.opened = 0 + p = self.style_list[style_name] + + # build font information + + f = p.get_font() + size = f.get_size()*2 + bgindex = self.color_map[p.get_background_color()] + fgindex = self.color_map[f.get_color()] + if f.get_type_face() == FONT_SERIF: + self.font_type = '\\f0\\fs%d\\cf%d\\cb%d' % (size,fgindex,bgindex) + else: + self.font_type = '\\f1\\fs%d\\cf%d\\cb%d' % (size,fgindex,bgindex) + if f.get_bold(): + self.font_type = self.font_type + "\\b" + if f.get_underline(): + self.font_type = self.font_type + "\\ul" + if f.get_italic(): + self.font_type = self.font_type + "\\i" + + # build paragraph information + + if not self.in_table: + self.f.write('\\pard') + if p.get_alignment() == PARA_ALIGN_RIGHT: + self.f.write('\\qr') + elif p.get_alignment() == PARA_ALIGN_CENTER: + self.f.write('\\qc') + self.f.write('\\ri%d' % twips(p.get_right_margin())) + self.f.write('\\li%d' % twips(p.get_left_margin())) + self.f.write('\\fi%d' % twips(p.get_first_indent())) + if p.get_alignment() == PARA_ALIGN_JUSTIFY: + self.f.write('\\qj') + if p.get_padding(): + self.f.write('\\sa%d' % twips(p.get_padding()/2.0)) + if p.get_top_border(): + self.f.write('\\brdrt\\brdrs') + if p.get_bottom_border(): + self.f.write('\\brdrb\\brdrs') + if p.get_left_border(): + self.f.write('\\brdrl\\brdrs') + if p.get_right_border(): + self.f.write('\\brdrr\\brdrs') + if p.get_first_indent(): + self.f.write('\\fi%d' % twips(p.get_first_indent())) + if p.get_left_margin(): + self.f.write('\\li%d' % twips(p.get_left_margin())) + if p.get_right_margin(): + self.f.write('\\ri%d' % twips(p.get_right_margin())) + + if leader: + self.opened = 1 + self.f.write('\\tx%d' % twips(p.get_left_margin())) + self.f.write('{%s ' % self.font_type) + self.write_text(leader) + self.f.write('\\tab}') + self.opened = 0 + + #-------------------------------------------------------------------- + # + # Ends a paragraph. Care has to be taken to make sure that the + # braces are closed properly. The self.opened flag is used to indicate + # if braces are currently open. If the last write was the end of + # a bold-faced phrase, braces may already be closed. + # + #-------------------------------------------------------------------- + def end_paragraph(self): + if not self.in_table: + self.f.write(self.text) + if self.opened: + self.f.write('}') + self.text = "" + self.opened = 0 + self.f.write('\n\\par') + else: + if self.text == "": + self.write_text(" ") + self.text = self.text + '}' + + #-------------------------------------------------------------------- + # + # Starts boldfaced text, enclosed the braces + # + #-------------------------------------------------------------------- + def start_bold(self): + if self.opened: + self.f.write('}') + self.f.write('{%s\\b ' % self.font_type) + self.opened = 1 + + #-------------------------------------------------------------------- + # + # Ends boldfaced text, closing the braces + # + #-------------------------------------------------------------------- + def end_bold(self): + self.opened = 0 + self.f.write('}') + + #-------------------------------------------------------------------- + # + # Start a table. Grab the table style, and store it. Keep a flag to + # indicate that we are in a table. This helps us deal with paragraphs + # internal to a table. RTF does not require anything to start a + # table, since a table is treated as a bunch of rows. + # + #-------------------------------------------------------------------- + def start_table(self,name,style_name): + self.in_table = 1 + self.tbl_style = self.table_styles[style_name] + + #-------------------------------------------------------------------- + # + # End a table. Turn off the table flag + # + #-------------------------------------------------------------------- + def end_table(self): + self.in_table = 0 + + #-------------------------------------------------------------------- + # + # Start a row. RTF uses the \trowd to start a row. RTF also specifies + # all the cell data after it has specified the cell definitions for + # the row. Therefore it is necessary to keep a list of cell contents + # that is to be written after all the cells are defined. + # + #-------------------------------------------------------------------- + def start_row(self): + self.contents = [] + self.cell = 0 + self.prev = 0 + self.cell_percent = 0.0 + self.f.write('\\trowd\n') + + #-------------------------------------------------------------------- + # + # End a row. Write the cell contents, separated by the \cell marker, + # then terminate the row + # + #-------------------------------------------------------------------- + def end_row(self): + self.f.write('{') + for line in self.contents: + self.f.write(line) + self.f.write('\\cell ') + self.f.write('}\\pard\\intbl\\row\n') + + #-------------------------------------------------------------------- + # + # Start a cell. Dump out the cell specifics, such as borders. Cell + # widths are kind of interesting. RTF doesn't specify how wide a cell + # is, but rather where it's right edge is in relationship to the + # left margin. This means that each cell is the cumlative of the + # previous cells plus its own width. + # + #-------------------------------------------------------------------- + def start_cell(self,style_name,span=1): + s = self.cell_styles[style_name] + self.remain = span -1 + if s.get_top_border(): + self.f.write('\\clbrdrt\\brdrs\\brdrw10\n') + if s.get_bottom_border(): + self.f.write('\\clbrdrb\\brdrs\\brdrw10\n') + if s.get_left_border(): + self.f.write('\\clbrdrl\\brdrs\\brdrw10\n') + if s.get_right_border(): + self.f.write('\\clbrdrr\\brdrs\\brdrw10\n') + table_width = float(self.get_usable_width()) + for cell in range(self.cell,self.cell+span): + self.cell_percent = self.cell_percent + float(self.tbl_style.get_column_width(cell)) + cell_width = twips((table_width * self.cell_percent)/100.0) + self.f.write('\\cellx%d\\pard\intbl\n' % cell_width) + self.cell = self.cell+1 + + #-------------------------------------------------------------------- + # + # End a cell. Save the current text in the content lists, since data + # must be saved until all cells are defined. + # + #-------------------------------------------------------------------- + def end_cell(self): + self.contents.append(self.text) + self.text = "" + + #-------------------------------------------------------------------- + # + # Add a photo. Embed the photo in the document. Use the Python + # imaging library to load and scale the photo. The image is converted + # to JPEG, since it is smaller, and supported by RTF. The data is + # dumped as a string of HEX numbers. + # + # If the PIL library is not loaded, ignore the request to load the + # photo. + # + #-------------------------------------------------------------------- + def add_photo(self,name,pos,x_cm,y_cm): + if no_pil: + return + + im = PIL.Image.open(name) + nx,ny = im.size + buf = im.tostring("jpeg","RGB") + + scale = float(ny)/float(nx) + if scale > 1: + scale = 1.0/scale + act_width = twips(x_cm * scale) + act_height = twips(y_cm * scale) + im.thumbnail((int(act_width*40),int(act_height*40))) + + self.f.write('{\*\shppict{\\pict\\jpegblip') + self.f.write('\\picwgoal%d\\pichgoal%d\n' % (act_width,act_height)) + index = 1 + for i in buf: + self.f.write('%02x' % ord(i)) + if index%32==0: + self.f.write('\n') + index = index+1 + self.f.write('}}\\par\n') + + #-------------------------------------------------------------------- + # + # Writes text. If braces are not currently open, open them. Loop + # character by character (terribly inefficient, but it works). If a + # character is 8 bit (>127), convert it to a hex representation in + # the form of \`XX. Make sure to escape braces. + # + #-------------------------------------------------------------------- + def write_text(self,text): + if self.opened == 0: + self.opened = 1 + self.text = self.text + '{%s ' % self.font_type + for i in text: + if ord(i) > 127: + self.text = self.text + '\\\'%2x' % ord(i) + elif i == '{' or i == '}' : + self.text = self.text + '\\%s' % i + else: + self.text = self.text + i + + +if __name__ == "__main__": + + paper = PaperStyle("Letter",27.94,21.59) + + styles = StyleSheet() + foo = FontStyle() + foo.set_type_face(FONT_SANS_SERIF) + foo.set_color((255,0,0)) + foo.set_size(24) + foo.set_underline(1) + foo.set_bold(1) + foo.set_italic(1) + + para = ParagraphStyle() + para.set_alignment(PARA_ALIGN_RIGHT) + para.set_font(foo) + styles.add_style("Title",para) + + foo = FontStyle() + foo.set_type_face(FONT_SERIF) + foo.set_size(12) + + para = ParagraphStyle() + para.set_font(foo) + styles.add_style("Normal",para) + + foo = FontStyle() + foo.set_type_face(FONT_SERIF) + foo.set_size(12) + + para = ParagraphStyle() + para.set_font(foo) + para.set_top_border(1) + para.set_left_border(1) + para.set_right_border(1) + para.set_bottom_border(1) + styles.add_style("Box",para) + + doc = RTFDoc(styles,paper,PAPER_PORTRAIT) + + cell = TableCellStyle() + cell.set_padding(0.2) + cell.set_top_border(1) + cell.set_bottom_border(1) + cell.set_right_border(1) + cell.set_left_border(1) + doc.add_cell_style('ParentHead',cell) + + cell = TableCellStyle() + cell.set_padding(0.1) + cell.set_bottom_border(1) + cell.set_left_border(1) + doc.add_cell_style('TextContents',cell) + + cell = TableCellStyle() + cell.set_padding(0.1) + cell.set_bottom_border(0) + cell.set_left_border(1) + cell.set_padding(0.1) + doc.add_cell_style('TextChild1',cell) + + cell = TableCellStyle() + cell.set_padding(0.1) + cell.set_bottom_border(1) + cell.set_left_border(1) + cell.set_padding(0.1) + doc.add_cell_style('TextChild2',cell) + + cell = TableCellStyle() + cell.set_padding(0.1) + cell.set_bottom_border(1) + cell.set_right_border(1) + cell.set_left_border(1) + doc.add_cell_style('TextContentsEnd',cell) + + cell = TableCellStyle() + cell.set_padding(0.2) + cell.set_bottom_border(1) + cell.set_right_border(1) + cell.set_left_border(1) + doc.add_cell_style('ChildName',cell) + + table = TableStyle() + table.set_width(100) + table.set_columns(3) + table.set_column_width(0,20) + table.set_column_width(1,40) + table.set_column_width(2,40) + doc.add_table_style('ParentTable',table) + + table = TableStyle() + table.set_width(100) + table.set_columns(4) + table.set_column_width(0,5) + table.set_column_width(1,15) + table.set_column_width(2,40) + table.set_column_width(3,40) + doc.add_table_style('ChildTable',table) + + doc.open("test") + + doc.start_paragraph("Title") + doc.write_text("My Title") + doc.end_paragraph() + + doc.start_paragraph("Normal") + doc.write_text("Hello there. This is fun") + doc.end_paragraph() + + doc.start_paragraph("Box") + doc.write_text("This is my box") + doc.end_paragraph() + + doc.start_paragraph("Normal") + doc.add_photo("foo.png",200,200) + doc.end_paragraph() + + doc.start_table(id,'ParentTable') + doc.start_row() + doc.start_cell('ParentHead',3) + doc.start_paragraph('Normal') + doc.write_text('Banana : Smith ') + doc.end_paragraph() + doc.end_cell() + doc.end_row() + + doc.start_row() + doc.start_cell("TextContents") + doc.start_paragraph('Normal') + doc.write_text("some event") + doc.end_paragraph() + doc.end_cell() + doc.start_cell("TextContents") + doc.start_paragraph('Normal') + doc.write_text("someday") + doc.end_paragraph() + doc.end_cell() + doc.start_cell("TextContentsEnd") + doc.start_paragraph('Normal') + doc.write_text("somewhere") + doc.end_paragraph() + doc.end_cell() + doc.end_row() + + doc.end_table() + + doc.close() + +Plugins.register_text_doc(_("Rich Text Format (RTF)"),RTFDoc,1,1,1) diff --git a/src/gramps_main.py b/src/gramps_main.py index 45ea49e81..dba3e0e7f 100755 --- a/src/gramps_main.py +++ b/src/gramps_main.py @@ -2009,6 +2009,8 @@ def main(arg): database = RelDataBase() + Plugins.load_plugins(const.docgenDir) + Plugins.load_plugins(os.path.expanduser("~/.gramps/docgen")) Plugins.load_plugins(const.pluginsDir) Plugins.load_plugins(os.path.expanduser("~/.gramps/plugins")) Filter.load_filters(const.filtersDir) diff --git a/src/plugins/AncestorChart.py b/src/plugins/AncestorChart.py index 83821e546..a720127c8 100644 --- a/src/plugins/AncestorChart.py +++ b/src/plugins/AncestorChart.py @@ -146,7 +146,7 @@ class AncestorChart: page = page + 1 generation = generation + 3 try: - self.doc.close() + self.doc.close() except: print _("Document write failure")