gramps/gramps2/src/docgen/LPRDoc.py

514 lines
18 KiB
Python
Raw Normal View History

#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2004 Donald N. Allingham
#
# Modifications and feature additions:
# 2002 Donald A. Peterson
#
# 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
#
"""LPR document generator"""
#------------------------------------------------------------------------
#
# python modules
#
#------------------------------------------------------------------------
import string
import pygtk
import gnomeprint, gnomeprint.ui, gtk
#------------------------------------------------------------------------
#
# gramps modules
#
#------------------------------------------------------------------------
import BaseDoc
import Plugins
import ImgManip
from gettext import gettext as _
#------------------------------------------------------------------------
#
# Paragraph Handling
#
#------------------------------------------------------------------------
#------------------------------------------------------------------------
#
# Units conversion
#
#------------------------------------------------------------------------
def cm(unit):
"""
Convert gnome-print units to cm
"""
return 2.54 * unit / 72.0
def unit(cms):
"""
Convert cms to gnome-print units
"""
return cms * 72.0 / 2.54
#------------------------------------------------------------------------
#
# LPRDoc
#
#------------------------------------------------------------------------
class LPRDoc(BaseDoc.BaseDoc):
"""Gnome-print document interface class. Derived from BaseDoc"""
def open(self,filename):
"""Sets up initialization"""
#set up variables needed to keep track of which state we are in
self.__in_table=0
self.__in_cell=0
self.__in_paragraph=0
self.__page_count=0
self.__page_open=0
self.__paragraph_data=""
self.__cell_data=""
self.__table_data=[]
#create main variables for this print job
self.__job = gnomeprint.Job(gnomeprint.config_default())
self.__pc = self.__job.get_context()
#find out what the width and height of the page is
__width, __height =gnomeprint.job_get_page_size_from_config(self.__job.get_config())
self.__left_margin=__width*0.1
self.__right_margin=__width*0.9
self.__top_margin=__height*0.9
self.__bottom_margin=__height*0.1
#set what fonts we will use
self.__regular_font=gnomeprint.font_find_closest("Serif Regular", 10)
self.__bold_font=gnomeprint.font_find_closest("Serif Bold", 10)
self.__font=self.__regular_font
self.start_page(self)
def close(self):
"""Clean up and close the document"""
#print "close doc"
#gracefully end page before we close the doc if a page is open
if self.__page_open:
self.end_page()
self.__job.close()
self.__show_print_dialog()
def line_break(self):
"Forces a line break within a paragraph"
self.__advance_line(self.__y)
def page_break(self):
"Forces a page break, creating a new page"
self.start_page()
def start_page(self,orientation=None):
"""Create a new page"""
#print "begin page"
#reset variables dealing with opening a page
if (self.__page_open):
self.end_page()
self.__page_open=1
self.__page_count+=1
self.__x=self.__left_margin
self.__y=self.__top_margin
self.__pc.beginpage(str(self.__page_count))
self.__pc.setfont(self.__font)
self.__pc.moveto(self.__x, self.__y)
def end_page(self):
"""Close the current page"""
#print "end page"
if (self.__page_open):
self.__page_open=0
self.__pc.showpage()
def start_paragraph(self,style_name,leader=None):
"""Paragraphs handling - A Gramps paragraph is any
single body of text, from a single word, to several sentences.
We assume a linebreak at the end of each paragraph."""
#print "start paragraph"
#set paragraph variables so we know that we are in a paragraph
self.__in_paragraph=1
self.__paragraph_data=""
def end_paragraph(self):
"""End the current paragraph"""
#print "end paragraph"
self.__in_paragraph=0
#print text in paragraph if any data exists
if len(self.__paragraph_data) > 0:
self.__x, self.__y=self.__print_text(self.__paragraph_data,
self.__x, self.__y,
self.__left_margin,
self.__right_margin)
self.__paragraph_data=""
self.__y=self.__advance_line(self.__y)
def start_bold(self):
"""Bold face"""
#print "start bold"
self.__font=self.__bold_font
self.__pc.setfont(self.__font)
def end_bold(self):
"""End bold face"""
#print "end bold"
self.__font=self.__regular_font
self.__pc.setfont(self.__font)
def start_superscript(self):
pass
def end_superscript(self):
pass
def start_listing(self,style_name):
"""
Starts a new listing block, using the specified style name.
style_name - name of the ParagraphStyle to use for the block.
"""
pass
def end_listing(self):
pass
def start_table(self,name,style_name):
"""Begin new table"""
#print "start table"
#reset variables for this state
self.__table_data=[]
self.__in_table=1
def end_table(self):
"""Close the table environment"""
#print "end table"
#output table contents
self.__output_table()
self.__in_table=0
self.__y=self.__advance_line(self.__y)
def start_row(self):
"""Begin a new row"""
# doline/skipfirst are flags for adding hor. rules
#print "start row"
#reset this state, so we can get data from user
self.__row_data=[]
def end_row(self):
"""End the row (new line)"""
#print "end row"
#add row data to the data we have for the current table
self.__table_data.append(self.__row_data)
def start_cell(self,style_name,span=1):
"""Add an entry to the table.
We always place our data inside braces
for safety of formatting."""
#print "start cell"
#reset this state
self.__in_cell=1
self.__cell_data=""
def end_cell(self):
"""Prepares for next cell"""
#print "end cell"
#append the cell text to the row data
self.__in_cell=0
self.__row_data.append(self.__cell_data)
def add_photo(self,name,pos,x,y):
"""Add photo to report"""
#print "add photo"
def horizontal_line(self):
self.__pc.moveto(self.__x, self.__y)
self.__pc.lineto(self.__right_margin, self.__y)
def write_cmdstr(self,text):
"""
Writes the text in the current paragraph. Should only be used after a
start_paragraph and before an end_paragraph.
text - text to write.
"""
if self__in_paragraph != 1:
self.start_paragraph()
self.write(text)
def draw_arc(self,style,x1,y1,x2,y2,angle,extent):
pass
def draw_path(self,style,path):
pass
def draw_box(self,style,text,x,y):
#assuming that we start drawing box from current position
__width=x-self.__x
__height=y-self.__y
self.__pc.rect_stroked(self.__x, self.__y)
if text != None:
__text_width=self.__get_text_width(text)
#try to center text in box
self.__pc.moveto(self.__x+(__width/2)-(__text_width/2),
self.__y+(__height/2))
self.__pc.show(text)
def write_at (self, style, text, x, y):
self.__pc.moveto(x, y)
self.__pc.show(text)
def draw_bar(self, style, x1, y1, x2, y2):
self.__pc.moveto(x1, y1)
self.__pc.lineto(x2, y2)
def draw_text(self,style,text,x1,y1):
self.__pc.moveto(x1,y1)
self.__pc.show(text)
def center_text(self,style,text,x1,y1):
#not sure how x1, y1 fit into this
#should we assume x1 y1 is the starting location
#and that the right margin is the right edge?
__width=self.get_text_width(text)
__center=self.__right_margin-self.__left_margin
__center-=__width/2
self.__pc.moveto(__center, self.__y)
self.__pc.show(text)
def rotate_text(self,style,text,x,y,angle):
pass
def draw_line(self,style,x1,y1,x2,y2):
self.__pc.line_stroked(x1,y1,x2,y2)
def write_text(self,text):
"""Write the text to the file"""
#print "write text"
#if we are in a cell add this text to cell_data
if self.__in_cell:
self.__cell_data=self.__cell_data+str(text)
return
#if we are in a paragraph add this text to the paragraph data
if self.__in_paragraph:
self.__paragraph_data=self.__paragraph_data+str(text)
return
#if we are at the bottom of the page, create a new page
if self.__y < self.__bottom_margin:
self.end_page()
self.start_page()
#output data if we get this far (we are not in a paragaph or
#a table)
self.__x, self.__y=self.__print_text(text, self.__x, self.__y,
self.__left_margin, self.__right_margin)
#self.__y=self.__advance_line(self.__y)
#function to help us advance a line
def __advance_line(self, y):
return y-20
#function to determine the width of text
def __text_width(self, text):
return self.__font.get_width_utf8(text)
#this function tells us the minimum size that a column can be
#by returning the width of the largest word in the text
def __min_column_size (self, text):
__textlist=string.split(text, " ")
__max_word_size=0
for __word in __textlist:
__length=self.__text_width(__word+" "*3)
if __length > __max_word_size:
__max_word_size=__length
return __max_word_size
#function to print out text between left_margin and right_margin
#at position y on page
def __print_text(self, text, x, y, left_margin, right_margin):
__width=right_margin-left_margin
#all text will fit within the width provided
if __width >= self.__text_width(text):
self.__pc.moveto(left_margin, y)
x=left_margin+self.__text_width(text)
self.__pc.show(text)
y=self.__advance_line(y)
else:
#divide up text and print
__textlist=string.split(text, " ")
__text=""
for __element in __textlist:
if self.__text_width(__text+__element+" ") < __width:
__text=__text+__element+" "
else:
#__text contains as many words as this __width allows
self.__pc.moveto(left_margin, y)
self.__pc.show(__text)
__text=__element+" "
y=self.__advance_line(y)
#if not in table and cursor is below bottom margin
if self.__in_table==0 and y < self.__bottom_margin:
self.end_page()
self.start_page()
x=self.__x
y=self.__y
#if __text still contains data, we will want to print it out
if len(__text) > 0:
self.__pc.moveto(left_margin, y)
self.__pc.show(__text)
y=self.__advance_line(y)
return (x,y)
def __output_table(self):
"""do calcs on data in table and output data in a formatted way"""
__max_col_size=[0]*100
__min_col_size=[0]*100
for __row in self.__table_data:
#do calcs on each __row and keep track on max length of each column
for __col in range(0,len(__row)):
__row[__col]=__row[__col]+" "*3;
if __max_col_size[__col] < self.__text_width(__row[__col]):
__max_col_size[__col]=self.__text_width(__row[__col])
__min_col_size[__col]=self.__min_column_size(__row[__col])
#now we have an idea of the max size of each column
#now output data in the table
#find total width that the table needs to be.
#later this value may be used to cut the longest columns down
#so that data fits on the width of the page
__total_table_width=0
for __value in __max_col_size:
__total_table_width+=__value
#is table width larger than the width of the paper?
if __total_table_width > (self.__right_margin - self.__left_margin):
#figure out the largest our table can be to fit on a page
__width=self.__right_margin - self.__left_margin
#find out how much larger our table is than what is allowed
__extra_length=__total_table_width - __width
#for each column, substract the extra width off so that
#each column gets deduced a width determined by its
#size compared to the other columns
#(larger columns get more taken off, smaller columns get
# less width taken off)
while __extra_length > 1:
print __extra_length
for __col in range(0, len(__max_col_size)):
if __extra_length<=1: break
if __max_col_size[__col] > __min_col_size[__col]:
__temp=__max_col_size[__col]-(__max_col_size[__col]/__total_table_width)*__extra_length
if __temp >= __min_col_size[__col]:
__max_col_size[__col]=__temp
__total_table_width=0
for __value in __max_col_size:
__total_table_width+=__value
__extra_length=__total_table_width - __width
#for now we will assume left justification of tables
#output data in table
__min_y=self.__y #need to keep track of tallest column of
#text in each row
for __row in self.__table_data:
__x=self.__left_margin #reset so that x is at margin
for __col in range(0,len(__row)):
__nothing, __y=self.__print_text(__row[__col],
self.__x, self.__y,
__x, __x+__max_col_size[__col])
__x=__x+__max_col_size[__col] # set up margin for this row
if __y < __min_y: # if we go below current lowest
__min_y=__y # column
self.__y=__min_y #reset so that we do not overwrite
#see if we are about to go off the page, if so, create new page
if self.__y < self.__bottom_margin:
self.end_page()
self.start_page()
__min_y=self.__y
#function to print text to a printer
def __do_print(self,dialog, job):
__pc = gnomeprint.Context(dialog.get_config())
job.render(__pc)
__pc.close()
#I believe this is a print preview
def __show_preview(self, dialog):
__w = gnomeprint.ui.JobPreview(self.__job, _("Print Preview"))
__w.set_property('allow-grow', 1)
__w.set_property('allow-shrink', 1)
__w.set_transient_for(dialog)
__w.show_all()
#function used to get users response and do a certain
#action depending on that response
def __print_dialog_response(self, dialog, resp, job):
if resp == gnomeprint.ui.DIALOG_RESPONSE_PREVIEW:
self.__show_preview(dialog)
elif resp == gnomeprint.ui.DIALOG_RESPONSE_CANCEL:
dialog.destroy()
elif resp == gnomeprint.ui.DIALOG_RESPONSE_PRINT:
self.__do_print(dialog, self.__job)
dialog.destroy()
#function displays a window that allows user to choose
#to print, show, etc
def __show_print_dialog(self):
__dialog = gnomeprint.ui.Dialog(self.__job, _("Print..."), 0)
__dialog.connect('response', self.__print_dialog_response, self.__job)
__dialog.show()
#------------------------------------------------------------------------
#
# Register the document generator with the system
#
#------------------------------------------------------------------------
Plugins.register_text_doc(
name=_("Print..."),
classref=LPRDoc,
table=1,
paper=1,
style=0,
ext=""
)