gramps/src/plugins/docgen/AsciiDoc.py

387 lines
14 KiB
Python
Raw Normal View History

#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# Copyright (C) 2007-2009 Brian G. Matherly
# Copyright (C) 2009 Benny Malengier <benny.malengier@gramps-project.org>
#
# 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
#
# $Id:AsciiDoc.py 9912 2008-01-22 09:17:46Z acraphae $
#------------------------------------------------------------------------
#
# python modules
#
#------------------------------------------------------------------------
from gettext import gettext as _
#------------------------------------------------------------------------
#
# Gramps modules
#
#------------------------------------------------------------------------
from gen.plug.docgen import BaseDoc, TextDoc,\
PARA_ALIGN_RIGHT, PARA_ALIGN_CENTER
from gen.plug import PluginManager, DocGenPlugin
import Errors
import Utils
2005-12-06 12:08:09 +05:30
#------------------------------------------------------------------------
#
# Constants
#
#------------------------------------------------------------------------
LEFT,RIGHT,CENTER = 'LEFT','RIGHT','CENTER'
_WIDTH_IN_CHARS = 72
#------------------------------------------------------------------------
#
# This routine was written by David Mertz and placed into the public
# domain. It is sample code from his book, "Text Processing in Python"
#
# Modified by Alex Roitman: right-pad with spaces, if right_pad==1;
# return empty string if no text was given
2005-12-06 12:08:09 +05:30
# Another argument: "first" is the first line indent in characters
# _relative_ to the "left" margin. It can be negative!
#
#------------------------------------------------------------------------
2005-12-06 12:08:09 +05:30
def reformat_para(para='',left=0,right=72,just=LEFT,right_pad=0,first=0):
if not para.strip():
return "\n"
words = para.split()
lines = []
line = ''
word = 0
end_words = 0
2005-12-06 12:08:09 +05:30
real_left = left+first
while not end_words:
2005-12-06 12:08:09 +05:30
if len(words[word]) > right-real_left: # Handle very long words
line = words[word]
word +=1
if word >= len(words):
end_words = 1
else: # Compose line of words
2005-12-06 12:08:09 +05:30
while len(line)+len(words[word]) <= right-real_left:
line += words[word]+' '
word += 1
if word >= len(words):
end_words = 1
break
lines.append(line)
2005-12-06 12:08:09 +05:30
real_left = left
line = ''
if just==CENTER:
if right_pad:
2005-12-06 12:08:09 +05:30
return '\n'.join(
[' '*(left+first) + ln.center(right-left-first)
for ln in lines[0:1] ] +
[ ' '*left + ln.center(right-left) for ln in lines[1:] ]
)
else:
2005-12-06 12:08:09 +05:30
return '\n'.join(
[' '*(left+first) + ln.center(right-left-first).rstrip()
for ln in lines[0:1] ] +
[' '*left + ln.center(right-left).rstrip()
for ln in lines[1:] ]
)
elif just==RIGHT:
if right_pad:
return '\n'.join([line.rjust(right) for line in lines])
else:
return '\n'.join([line.rjust(right).rstrip() for line in lines])
else: # left justify
if right_pad:
2005-12-06 12:08:09 +05:30
return '\n'.join(
[' '*(left+first) + line.ljust(right-left-first)
for line in lines[0:1] ] +
[' '*left + line.ljust(right-left) for line in lines[1:] ]
)
else:
2005-12-06 12:08:09 +05:30
return '\n'.join(
[' '*(left+first) + line for line in lines[0:1] ] +
[' '*left + line for line in lines[1:] ]
)
#------------------------------------------------------------------------
#
# Ascii
#
#------------------------------------------------------------------------
class AsciiDoc(BaseDoc,TextDoc):
#--------------------------------------------------------------------
#
# Opens the file, resets the text buffer.
#
#--------------------------------------------------------------------
def open(self,filename):
if filename[-4:] != ".txt":
self.filename = filename + ".txt"
else:
self.filename = filename
try:
self.f = open(self.filename,"w")
except IOError,msg:
errmsg = "%s\n%s" % (_("Could not create %s") % self.filename, msg)
raise Errors.ReportError(errmsg)
except:
raise Errors.ReportError(_("Could not create %s") % self.filename)
self.in_cell = 0
self.text = ""
#--------------------------------------------------------------------
#
# Close the file. Call the app if required.
#
#--------------------------------------------------------------------
def close(self):
self.f.close()
if self.open_req:
Utils.open_file_with_default_application(self.filename)
def get_usable_width(self):
return _WIDTH_IN_CHARS
#--------------------------------------------------------------------
#
# Force a section page break
#
#--------------------------------------------------------------------
def page_break(self):
self.f.write('\012')
def start_bold(self):
pass
def end_bold(self):
pass
def start_superscript(self):
self.text = self.text + '['
def end_superscript(self):
self.text = self.text + ']'
#--------------------------------------------------------------------
#
# Starts a paragraph.
#
#--------------------------------------------------------------------
def start_paragraph(self,style_name,leader=None):
styles = self.get_style_sheet()
self.p = styles.get_paragraph_style(style_name)
self.leader = leader
#--------------------------------------------------------------------
#
# End a paragraph. First format it to the desired widths.
# If not in table cell, write it immediately. If in the cell,
# add it to the list for this cell after formatting.
#
#--------------------------------------------------------------------
def end_paragraph(self):
if self.p.get_alignment() == PARA_ALIGN_RIGHT:
fmt = RIGHT
elif self.p.get_alignment() == PARA_ALIGN_CENTER:
fmt = CENTER
else:
fmt = LEFT
if self.in_cell:
right = self.cell_widths[self.cellnum]
else:
right = self.get_usable_width()
2005-12-06 12:08:09 +05:30
# Compute indents in characters. Keep first_indent relative!
regular_indent = 0
first_indent = 0
if self.p.get_left_margin():
2005-12-06 12:08:09 +05:30
regular_indent = int(4*self.p.get_left_margin())
if self.p.get_first_indent():
first_indent = int(4*self.p.get_first_indent())
if self.in_cell and self.cellnum < self.ncols - 1:
right_pad = 1
the_pad = ' '*right
else:
right_pad = 0
the_pad = ''
2005-12-06 12:08:09 +05:30
# Depending on the leader's presence, treat the first line differently
if self.leader:
# If we have a leader then we need to reformat the text
# as if there's no special treatment for the first line.
# Then add leader and eat up the beginning of the first line pad.
start_at = regular_indent + min(len(self.leader)+first_indent,0)
this_text = reformat_para(self.text,regular_indent,right,fmt,
right_pad)
this_text = ' '*(regular_indent+first_indent) + \
self.leader + this_text[start_at:]
else:
2005-12-06 12:08:09 +05:30
# If no leader then reformat the text according to the first
# line indent, as specified by style.
this_text = reformat_para(self.text,regular_indent,right,fmt,
right_pad,first_indent)
2005-12-06 12:08:09 +05:30
this_text += '\n' + the_pad + '\n'
if self.in_cell:
2005-12-06 12:08:09 +05:30
self.cellpars[self.cellnum] = self.cellpars[self.cellnum] + \
this_text
else:
self.f.write(this_text)
self.text = ""
#--------------------------------------------------------------------
#
# Start a table. Grab the table style, and store it.
#
#--------------------------------------------------------------------
def start_table(self, name,style_name):
styles = self.get_style_sheet()
self.tbl_style = styles.get_table_style(style_name)
self.ncols = self.tbl_style.get_columns()
#--------------------------------------------------------------------
#
# End a table. Turn off the self.in_cell flag
#
#--------------------------------------------------------------------
def end_table(self):
self.in_cell = 0
#--------------------------------------------------------------------
#
# Start a row. Initialize lists for cell contents, number of lines,
# and the widths. 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.cellpars = [''] * self.ncols
self.cell_lines = [0] * self.ncols
self.cell_widths = [0] * self.ncols
self.cellnum = -1
self.maxlines = 0
table_width = self.get_usable_width() * self.tbl_style.get_width() / 100.0
for cell in range(self.ncols):
self.cell_widths[cell] = int( table_width * \
self.tbl_style.get_column_width(cell) / 100.0 )
#--------------------------------------------------------------------
#
# End a row. Write the cell contents. Write the line of spaces
# if the cell has fewer lines than the maximum number.
#
#--------------------------------------------------------------------
def end_row(self):
self.in_cell = 0
cell_text = [None]*self.ncols
for cell in range(self.ncols):
if self.cell_widths[cell]:
blanks = ' '*self.cell_widths[cell] + '\n'
if self.cell_lines[cell] < self.maxlines:
self.cellpars[cell] = self.cellpars[cell] \
+ blanks * (self.maxlines-self.cell_lines[cell])
cell_text[cell] = self.cellpars[cell].split('\n')
for line in range(self.maxlines):
for cell in range(self.ncols):
if self.cell_widths[cell]:
self.f.write(cell_text[cell][line])
self.f.write('\n')
#--------------------------------------------------------------------
#
# Start a cell. Set the self.in_cell flag, increment the curren cell number.
#
#--------------------------------------------------------------------
def start_cell(self,style_name,span=1):
self.in_cell = 1
self.cellnum = self.cellnum + span
span = span - 1
while span:
self.cell_widths[self.cellnum] += \
self.cell_widths[self.cellnum-span]
self.cell_widths[self.cellnum-span] = 0
span = span - 1
#--------------------------------------------------------------------
#
# End a cell. Find out the number of lines in this cell, correct
# the maximum number of lines if necessary.
#
#--------------------------------------------------------------------
def end_cell(self):
self.in_cell = 0
self.cell_lines[self.cellnum] = self.cellpars[self.cellnum].count('\n')
if self.cell_lines[self.cellnum] > self.maxlines:
self.maxlines = self.cell_lines[self.cellnum]
def add_media_object(self, name, align, w_cm, h_cm, alt=''):
this_text = '(photo)'
if self.in_cell:
self.cellpars[self.cellnum] = self.cellpars[self.cellnum] + this_text
else:
self.f.write(this_text)
def write_note(self,text,format,style_name):
if format == 1:
for line in text.split('\n'):
self.start_paragraph(style_name)
self.write_text(line)
self.end_paragraph()
elif format == 0:
for line in text.split('\n\n'):
self.start_paragraph(style_name)
line = line.replace('\n',' ')
line = ' '.join(line.split())
self.write_text(line)
self.end_paragraph()
#--------------------------------------------------------------------
#
# Writes text.
#--------------------------------------------------------------------
def write_text(self,text,mark=None):
self.text = self.text + text
#------------------------------------------------------------------------
#
# register_plugin
#
#------------------------------------------------------------------------
def register_plugin():
"""
Register the document generator with the GRAMPS plugin system.
"""
pmgr = PluginManager.get_instance()
plugin = DocGenPlugin(name = _("Plain Text"),
description = _("Generates documents in plain text "
"format (.txt)."),
basedoc = AsciiDoc,
paper = True,
style = True,
extension = "txt" )
pmgr.register_plugin(plugin)
register_plugin()