# # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2000-2005 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 # # Written by Billy C. Earney, 2003-2004 # Modified by Alex Roitman, 2004 # $Id$ """LPR document generator""" #------------------------------------------------------------------------ # # python modules # #------------------------------------------------------------------------ import string from gettext import gettext as _ #------------------------------------------------------------------------ # # GNOME/GTK Modules # #------------------------------------------------------------------------ import gtk.gdk import gnomeprint, gnomeprint.ui ### FIXME ### if gnomeprint.Context.__dict__.has_key('grestore'): support_photos = 1 else: support_photos = 0 print "LPRDoc: Photos and rotated text (used in FanChart)" print " are not supported for direct printing." print " Get gnome-python from CVS" print " or wait for the next gnome-python release." ### end FIXME ### #------------------------------------------------------------------------ # # gramps modules # #------------------------------------------------------------------------ import BaseDoc import PluginMgr #------------------------------------------------------------------------ # # Constants # #------------------------------------------------------------------------ # Spacing in points (distance between the bottoms of two adjacent lines) _LINE_SPACING = 20 # Elevation of superscripts: a fraction of it's size _SUPER_ELEVATION_FRACTION = 0.3 # Number of points to subtract to get the superscrip size _SUPER_SIZE_REDUCTION = 2 # Factor which multiplies the font size to get line spacing for the font _EXTRA_SPACING_FACTOR = 1.1 # Font constants -- specific for gnome-print _TTF_FREEFONT = ( ('FreeSerif Medium','FreeSerif Bold','FreeSerif Italic','FreeSerif BoldItalic' ), ('FreeSans Medium','FreeSans Bold','FreeSans Oblique','FreeSans BoldOblique'), ('FreeMono Medium','FreeMono Bold','FreeMono Oblique','FreeMono BoldOblique') ) _MS_TTFONT = ( ('Times New Roman Regular','Times New Roman Bold','Times New Roman Italic','Times New Roman Bold Italic' ), ('Arial Regular','Arial Bold','Arial Italic','Arial Bold Italic'), ('Courier New Regular','Courier New Bold','Courier New Italic','Courier New Bold Italic') ) _GNOME_FONT = ( ('Serif Regular','Serif Bold','Serif Italic','Serif Bold Italic' ), ('Sans Regular','Sans Bold','Sans Italic','Sans Bold Italic'), ('Monospace Regular','Monospace New Bold','Monospace New Italic','Monospace New Bold Italic') ) # Search for ttf-freefont first ttf_not_found = 0 for family in _TTF_FREEFONT: for font in family: if font not in gnomeprint.font_list(): ttf_not_found = 1 break if ttf_not_found: print "LPRDoc: Free true type fonts not found." # Search for MS ttfs ms_not_found = 0 for family in _MS_TTFONT: for font in family: if font not in gnomeprint.font_list(): ms_not_found = 1 break if ms_not_found: print " Microsoft true type fonts not found." print " Using Gnome standard fonts." print " Non-ascii characters will appear garbled in the output." print " INSTALL Free true type fonts" print " from http://www.nongnu.org/freefont/" _FONT_SET = _GNOME_FONT else: print " Found Microsoft true type fonts. Will use them for now." print " These fonts are not free. " print " You are advised to switch to Free true type fonts" print " INSTALL Free true type fonts" print " from http://www.nongnu.org/freefont/" _FONT_SET = _MS_TTFONT else: _FONT_SET = _TTF_FREEFONT # Formatting directive constants _LINE_BREAK = "Break" _BOLD = "Bold" _SUPER = "Super" _MONO = "Mono" #------------------------------------------------------------------------ # # Units conversion # #------------------------------------------------------------------------ def cm2u(cm): """ Convert cm to gnome-print units. """ return cm * 72.0 / 2.54 #------------------------------------------------------------------------ # # font lookup function # #------------------------------------------------------------------------ def find_font_from_fontstyle(fontstyle): """ This function returns the gnomeprint.Font() object instance corresponding to the parameters of BaseDoc.FontStyle() object. fontstyle - a BaseDoc.FontStyle() instance """ if fontstyle.get_type_face() == BaseDoc.FONT_SERIF: family = _FONT_SET[0] elif fontstyle.get_type_face() == BaseDoc.FONT_SANS_SERIF: family = _FONT_SET[1] elif fontstyle.get_type_face() == BaseDoc.FONT_MONOSPACE: family = _FONT_SET[2] if fontstyle.get_bold(): if fontstyle.get_italic(): font = family[3] else: font = family[1] elif fontstyle.get_italic(): font = family[2] else: font = family[0] size = fontstyle.get_size() return gnomeprint.font_find_closest(font,size) #------------------------------------------------------------------------ # # basic font-specific text formatting functions # #------------------------------------------------------------------------ def get_text_width(text,fontstyle): """ This function returns the width of text using given fontstyle when not formatted. text - a text whose width to find fontstyle - a BaseDoc.FontStyle() instance """ font = find_font_from_fontstyle(fontstyle) return font.get_width_utf8(text) #------------------------------------------------------------------------ # # add to paragraph taking care of the newline characters # #------------------------------------------------------------------------ def append_to_paragraph(paragraph,directive,text): """ Add a piece to the paragraph while taking care of the newline characters. paragraph - a GnomePrintParagraph() instance directive - what to do with this piece text - the text of the corresponding piece """ if not directive and not text: return text_list = text.split('\n') for the_text in text_list[:-1]: paragraph.add_piece(directive,the_text) paragraph.add_piece(_LINE_BREAK,"") paragraph.add_piece(directive,text_list[-1:][0]) #------------------------------------------------------------------------ # # Paragraph class # #------------------------------------------------------------------------ class GnomePrintParagraph: """ A paragraph abstraction which provides the means for in-paragraph formatting. """ def __init__(self,paragraph_style): """ Creates a GnomePrintParapgrah instance. paragraph_style - an instance of BaseDoc paragraph style object """ self.style = paragraph_style self.fontstyle = self.style.get_font() self.piece_list = [] self.lines = [] self.height = None def add_piece(self,directive,text): """ Add a piece to the paragraph. directive - what to do with this piece text - the text of the corresponding piece """ self.piece_list.append((directive,text)) def get_piece_list(self): """ Return a list of pieces for the paragraph. """ return self.piece_list def get_fontstyle(self): """ Return fontstyle for the paragraph. """ return self.fontstyle def get_alignment(self): """ Return requested alignment of the paragraph. """ return self.style.get_alignment() def get_min_width(self): """ Determine the minimal width of the paragraph (longest word). """ max_word_size = 0 for (directive,text) in self.piece_list: fontstyle = BaseDoc.FontStyle(self.fontstyle) if directive == _BOLD: fontstyle.set_bold(1) elif directive == _SUPER: size = fontstyle.get_size() fontstyle.set_size(size-_SUPER_SIZE_REDUCTION) elif directive == _MONO: fontstyle.set_type_face(BaseDoc.FONT_MONOSPACE) for word in text.split(): length = get_text_width(word,fontstyle) if length > max_word_size: max_word_size = length return max_word_size def get_height(self,width): """ Determine the height the paragraph would have if formatted for a given width. width - required formatting width """ if not self.lines: self.format(width) return self.height def format(self,width): """ Format the paragraph for a given width. This is a complex procedure. It assembles lines from the paragraph's pieces. It also sets the height of the whole paragraph and the widths available after the lines are assembled. width - required formatting width """ if self.lines: return width = width - cm2u(self.style.get_right_margin()) \ - cm2u(self.style.get_left_margin()) nlines = 1 avail_width = width start_piece = end_piece = start_word = end_word = 0 first = 1 for piece_num in range(len(self.piece_list)): end_piece = piece_num (directive,text) = self.piece_list[piece_num] fontstyle = BaseDoc.FontStyle(self.fontstyle) if directive == _BOLD: fontstyle.set_bold(1) elif directive == _SUPER: size = fontstyle.get_size() fontstyle.set_size(size-_SUPER_SIZE_REDUCTION) elif directive == _MONO: fontstyle.set_type_face(BaseDoc.FONT_MONOSPACE) if first: first = 0 avail_width = avail_width - cm2u(self.style.get_first_indent()) if text and avail_width > get_text_width(text,fontstyle): avail_width -= get_text_width(text,fontstyle) end_word = len(text.split()) elif directive == _LINE_BREAK: nlines += 1 end_word = 0 self.lines.append((start_piece,start_word,end_piece,end_word,avail_width)) avail_width = width start_piece = end_piece start_word = 0 elif text and avail_width <= get_text_width(text,fontstyle): # divide up text textlist = text.split() the_text = "" for word_num in range(len(textlist)): word = textlist[word_num] if get_text_width(the_text + word + " ",fontstyle) <= avail_width: the_text = the_text + word + " " else: # the_text contains as much as avail_width allows nlines += 1 end_word = word_num avail_width -= get_text_width(the_text,fontstyle) self.lines.append((start_piece,start_word,end_piece,end_word,avail_width)) avail_width = width the_text = word + " " start_piece = end_piece start_word = word_num # if the_text still contains data, we will want to print it out if the_text: avail_width = width - get_text_width(the_text,fontstyle) end_word = len(textlist) self.lines.append((start_piece,start_word,end_piece,end_word,avail_width)) self.height = nlines * self.fontstyle.get_size() * _EXTRA_SPACING_FACTOR \ + 2 * cm2u(self.style.get_padding()) def get_lines(self): """ Return a list of assemlbed lines for the paragraph. Each element is a tuple corresponding to the line's contents: (start_piece,start_word,end_piece,end_word,avail_width) """ return self.lines #------------------------------------------------------------------------ # # Photo class # #------------------------------------------------------------------------ class GnomePrintPhoto: """ A photo abstraction which provides the means for correct photo placement. Way less complex that paragraph, but still useful. """ def __init__(self,name,pos,x_size,y_size): """ Creates a GnomePrintPhoto instance. """ self.name = name self.alignment = pos self.pixbuf = gtk.gdk.pixbuf_new_from_file(name) self.height = self.pixbuf.get_height() self.width = self.pixbuf.get_width() max_size = cm2u(max(x_size,y_size)) self.scale_x = int( max_size * float(self.width)/max(self.height,self.width) ) self.scale_y = int( max_size * float(self.height)/max(self.height,self.width) ) def get_image(self): """ Return the raw image of the photo. """ return self.pixbuf.get_pixels() def get_has_alpha(self): """ Return has_alpha of the photo. """ return self.pixbuf.get_has_alpha() def get_rowstride(self): """ Return the rowstride of the photo. """ return self.pixbuf.get_rowstride() def get_height(self,width=None): """ Return the real height of the photo as it should appear on the page. """ return self.scale_y def get_width(self): """ Return the real width of the photo as it should appear on the page. """ return self.scale_x def get_min_width(self): """ Return the minimum width of the photo as it should appear on the page. """ return self.scale_x def get_image_height(self): """ Return the height of the photo in terms of image's pixels. """ return self.height def get_image_width(self): """ Return the width of the photo in terms of image's pixels. """ return self.width def get_alignment(self): """ Return the alignment of the photo. """ return self.alignment #------------------------------------------------------------------------ # # LPRDoc class # #------------------------------------------------------------------------ class LPRDoc(BaseDoc.BaseDoc): """Gnome-print document interface class. Derived from BaseDoc.""" #------------------------------------------------------------------------ # # General methods # #------------------------------------------------------------------------ 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.page_count = 0 self.page_open = 0 self.brand_new_page = 0 self.paragraph = None self.cell_data = [] self.table_data = [] #create main variables for this print job self.job = gnomeprint.Job(gnomeprint.config_default()) self.gpc = 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 = cm2u(self.get_left_margin()) self.right_margin = width - cm2u(self.get_right_margin()) self.top_margin = height - cm2u(self.get_top_margin()) self.bottom_margin = cm2u(self.get_bottom_margin()) self.start_page(self) def close(self): """Clean up and close the document.""" #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 start_page(self,orientation=None): """Create a new page.""" # Don't start new page if it is just started if self.brand_new_page: return #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.gpc.beginpage(str(self.page_count)) self.gpc.moveto(self.x, self.y) self.brand_new_page = 1 def end_page(self): """Close the current page.""" if (self.page_open): self.page_open = 0 self.gpc.showpage() self.brand_new_page = 0 def page_break(self): "Forces a page break, creating a new page." # If we're already at the very top, relax and do nothing if not self.brand_new_page: self.end_page() self.start_page() #------------------------------------------------------------------------ # # Text methods # #------------------------------------------------------------------------ def string_width(self,fontstyle,text): "Override generic Fontscale-based width." return get_text_width(text,fontstyle) def line_break(self): "Forces a line break within a paragraph." # Add previously held text to the paragraph, # then add line break directive, # then start accumulating further text append_to_paragraph(self.paragraph,self.paragraph_directive,self.paragraph_text) self.paragraph.add_piece(_LINE_BREAK,"") self.paragraph_text = "" self.brand_new_page = 0 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.""" # Instantiate paragraph object and initialize buffers self.paragraph = GnomePrintParagraph(self.style_list[style_name]) self.paragraph_directive = "" self.paragraph_text = "" if leader: self.paragraph_text += leader + " " self.brand_new_page = 0 def end_paragraph(self): """End the current paragraph.""" # Add current text/directive to paragraoh, # then either add paragrah to the list of cell's paragraphs # or print it right away if not in cell append_to_paragraph(self.paragraph,self.paragraph_directive,self.paragraph_text) if self.in_cell: # We're inside cell. Add paragrah to celldata self.cell_data.append(self.paragraph) else: # paragraph not in table: write it right away self.x, self.y = self.write_paragraph(self.paragraph, self.x, self.y, self.right_margin - self.left_margin) self.paragraph = None self.brand_new_page = 0 def start_bold(self): """Bold face.""" append_to_paragraph(self.paragraph,self.paragraph_directive,self.paragraph_text) self.paragraph_directive = _BOLD self.paragraph_text = "" self.brand_new_page = 0 def end_bold(self): """End bold face.""" append_to_paragraph(self.paragraph,self.paragraph_directive,self.paragraph_text) self.paragraph_directive = "" self.paragraph_text = "" self.brand_new_page = 0 def start_superscript(self): append_to_paragraph(self.paragraph,self.paragraph_directive,self.paragraph_text) self.paragraph_directive = _SUPER self.paragraph_text = "" self.brand_new_page = 0 def end_superscript(self): append_to_paragraph(self.paragraph,self.paragraph_directive,self.paragraph_text) self.paragraph_directive = "" self.paragraph_text = "" self.brand_new_page = 0 def start_table(self,name,style_name): """Begin new table.""" # initialize table, compute its width, find number of columns self.table_data = [] self.in_table = 1 self.tbl_style = self.table_styles[style_name] self.ncols = self.tbl_style.get_columns() self.rownum = -1 self.table_width = (self.right_margin - self.left_margin) * \ self.tbl_style.get_width() / 100.0 self.cell_widths = [] self.gp_cell_styles = [] self.brand_new_page = 0 def end_table(self): """Close the table environment.""" # output table contents self.output_table() self.in_table = 0 self.y = self.advance_line(self.y) self.brand_new_page = 0 def start_row(self): """Begin a new row.""" # Initialize row, compute cell widths self.row_data = [] self.rownum = self.rownum + 1 self.cellnum = -1 self.span = 1 self.cell_widths.append([0] * self.ncols) self.gp_cell_styles.append([None] * self.ncols) for cell in range(self.ncols): self.cell_widths[self.rownum][cell] = self.table_width * \ self.tbl_style.get_column_width(cell) / 100.0 self.brand_new_page = 0 def end_row(self): """End the row (new line).""" # add row data to the data we have for the current table self.table_data.append(self.row_data) self.brand_new_page = 0 def start_cell(self,style_name,span=1): """Add an entry to the table.""" # Initialize a cell, take care of span>1 cases self.brand_new_page = 0 self.in_cell = 1 self.cell_data = [] self.cellnum = self.cellnum + self.span self.span = span self.gp_cell_styles[self.rownum][self.cellnum] = \ self.cell_styles[style_name] for extra_cell in range(1,span): self.cell_widths[self.rownum][self.cellnum] += \ self.cell_widths[self.rownum][self.cellnum + extra_cell] self.cell_widths[self.rownum][self.cellnum + extra_cell] = 0 def end_cell(self): """Prepares for next cell.""" # append the cell text to the row data self.in_cell = 0 self.row_data.append(self.cell_data) self.brand_new_page = 0 def add_media_object(self,name,pos,x,y): """Add photo to report.""" photo = GnomePrintPhoto(name,pos,x,y) if self.in_cell: # We're inside cell. Add photo to celldata self.cell_data.append(photo) else: # photo not in table: write it right away self.x, self.y = self.write_photo(photo, self.x, self.y, self.right_margin - self.left_margin) self.brand_new_page = 0 def write_photo(self,photo,x,y,alloc_width): """ Write the photo. photo - GnomePrintPhoto instance x,y - coordinates to start at alloc_width - allocated width """ self.brand_new_page = 0 # FIXME -- remove when gnome-python is released and hits every distro if not support_photos: return (x,y) # end FIXME width = photo.get_width() height = photo.get_height() if y - height < self.bottom_margin: self.end_page() self.start_page() y = self.y if photo.get_alignment() == 'center': add_x = 0.5* (alloc_width - width) elif photo.get_alignment() == 'right': add_x = alloc_width - width else: add_x = 0 self.gpc.gsave() self.gpc.translate(x+add_x,y-height) self.gpc.scale(width,height) if photo.get_has_alpha(): self.gpc.rgbaimage(photo.get_image(), photo.get_image_width(), photo.get_image_height(), photo.get_rowstride()) else: self.gpc.rgbimage(photo.get_image(), photo.get_image_width(), photo.get_image_height(), photo.get_rowstride()) self.gpc.grestore() x = x y = y - height return (x,y) def write_text(self,text): """Add the text to the paragraph""" self.brand_new_page = 0 # Take care of superscript tags super_count = text.count('') for num in range(super_count): start = text.find('') self.paragraph_text = self.paragraph_text + text[:start] append_to_paragraph(self.paragraph,self.paragraph_directive,self.paragraph_text) self.paragraph_text = "" text = text[start+7:] start = text.find('') self.paragraph_text = self.paragraph_text + text[:start] append_to_paragraph(self.paragraph,_SUPER,self.paragraph_text) self.paragraph_text = "" text = text[start+8:] self.paragraph_text = self.paragraph_text + text def write_note(self,text,format,style_name): self.brand_new_page = 0 if format == 1: for line in text.split('\n'): self.start_paragraph(style_name) self.paragraph_directive = _MONO 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 = string.join(string.split(line)) self.write_text(line) self.end_paragraph() #function to help us advance a line def advance_line(self,y,paragraph=None): self.brand_new_page = 0 if paragraph: spacing = paragraph.fontstyle.get_size() * _EXTRA_SPACING_FACTOR else: spacing = _LINE_SPACING new_y = y - spacing if y < self.bottom_margin: x = self.x self.end_page() self.start_page() new_y = self.y self.x = x return new_y def write_paragraph(self,paragraph,x,y,width): """ Write the contents of the paragraph, observing per-piece info. paragraph - GnomePrintParagraph instance x,y - coordinates to start at width - allocated width """ self.brand_new_page = 0 if not paragraph.get_piece_list(): return (x,y) paragraph.format(width) x = x + cm2u(paragraph.style.get_left_margin()) width = width - cm2u(paragraph.style.get_right_margin()) \ - cm2u(paragraph.style.get_left_margin()) left_margin = x no_space = 0 first = 1 if y - paragraph.fontstyle.get_size() * _EXTRA_SPACING_FACTOR < self.bottom_margin: self.end_page() self.start_page() x = left_margin y = self.y if y != self.top_margin: y = y - cm2u(paragraph.style.get_padding()) # Loop over lines which were assembled by paragraph.format() for (start_piece,start_word,end_piece,end_word,avail_width) \ in paragraph.get_lines(): if paragraph.get_alignment() == BaseDoc.PARA_ALIGN_CENTER: x = x + 0.5 * avail_width elif paragraph.get_alignment() == BaseDoc.PARA_ALIGN_RIGHT: x = x + avail_width elif paragraph.get_alignment() == BaseDoc.PARA_ALIGN_LEFT: pass elif paragraph.get_alignment() == BaseDoc.PARA_ALIGN_JUSTIFY: print "LPRDoc: Paragraph justification not supported." print " Falling back to left-justified mode." if first: first = 0 x = x + cm2u(paragraph.style.get_first_indent()) y = y - paragraph.fontstyle.get_size() * _EXTRA_SPACING_FACTOR # Loop over pieces that constitute the line for piece_num in range(start_piece,end_piece+1): (directive,text) = paragraph.get_piece_list()[piece_num] fontstyle = BaseDoc.FontStyle(paragraph.get_fontstyle()) if directive == _BOLD: fontstyle.set_bold(1) elif directive == _SUPER: size = fontstyle.get_size() fontstyle.set_size(size-_SUPER_SIZE_REDUCTION) y = y + _SUPER_ELEVATION_FRACTION * fontstyle.get_size() elif directive == _MONO: fontstyle.set_type_face(BaseDoc.FONT_MONOSPACE) textlist = text.split() if start_piece == end_piece: the_textlist = textlist[start_word:end_word] elif piece_num > start_piece and piece_num < end_piece: the_textlist = textlist[:] elif piece_num == start_piece: the_textlist = textlist[start_word:] elif piece_num == end_piece: the_textlist = textlist[:end_word] the_text = string.join(the_textlist) if piece_num == start_piece \ or directive == _SUPER \ or no_space \ or (the_text and the_text[0] in string.punctuation): spacer = "" else: spacer = " " the_text = spacer + the_text self.gpc.setfont(find_font_from_fontstyle(fontstyle)) self.gpc.moveto(x, y) self.gpc.show(the_text) x = x + get_text_width(the_text,fontstyle) if directive == _SUPER: y = y - _SUPER_ELEVATION_FRACTION * fontstyle.get_size() # If this was the linebreak, no space on the next line's start if end_word: no_space = 0 else: no_space = 1 y = self.advance_line(y,paragraph) x = left_margin x = x - cm2u(paragraph.style.get_left_margin()) y = y - cm2u(paragraph.style.get_padding()) return (x,y) def output_table(self): """Do calcs on data in table and output data in a formatted way.""" self.brand_new_page = 0 min_col_size = [0] * self.ncols max_vspace = [0] * len(self.table_data) for row_num in range(len(self.table_data)): row = self.table_data[row_num][:] #do calcs on each row and keep track on max length of each column for col in range(self.ncols): if not self.cell_widths[row_num][col]: continue padding = cm2u(self.gp_cell_styles[row_num][col].get_padding()) the_max = 0 for paragraph in row[col]: the_min = paragraph.get_min_width() if the_min > min_col_size[col]: min_col_size[col] = the_min the_max += paragraph.get_height( self.cell_widths[row_num][col]) the_max += 2 * padding if the_max > max_vspace[row_num]: max_vspace[row_num] = the_max #is table width larger than the width of the paper? min_table_width = 0 for size in min_col_size: min_table_width = min_table_width + size if min_table_width > (self.right_margin - self.left_margin): print "LPRDoc: Table does not fit onto the page." #for now we will assume left justification of tables #output data in table for row_num in range(len(self.table_data)): row = self.table_data[row_num] # If this row puts us below the bottom, start new page here if self.y - max_vspace[row_num] < self.bottom_margin: self.end_page() self.start_page() x = self.left_margin #reset so that x is at margin col_y = self.y # all columns start at the same height for col in range(self.ncols): if not self.cell_widths[row_num][col]: continue self.y = col_y padding = cm2u(self.gp_cell_styles [row_num][col].get_padding()) for paragraph in row[col]: if paragraph.__class__.__name__ == 'GnomePrintPhoto': write_item = self.write_photo else: write_item = self.write_paragraph junk, self.y = write_item(paragraph, x + padding, self.y - padding, self.cell_widths[row_num][col] \ - 2 * padding) x = x + self.cell_widths[row_num][col] # set up margin for this row self.y = col_y - max_vspace[row_num] #------------------------------------------------------------------------ # # Graphic methods # #------------------------------------------------------------------------ def horizontal_line(self): self.brand_new_page = 0 self.gpc.moveto(self.left_margin, self.y) self.gpc.lineto(self.right_margin, self.y) def draw_path(self,style,path): self.brand_new_page = 0 stype = self.draw_styles[style] color = [ val/255.0 for val in stype.get_fill_color()] point = path[0] x = cm2u(point[0]) + self.left_margin y = self.top_margin - cm2u(point[1]) self.gpc.moveto(x,y) for point in path[1:]: x = cm2u(point[0]) + self.left_margin y = self.top_margin - cm2u(point[1]) self.gpc.lineto(x,y) self.gpc.closepath() self.gpc.stroke() point = path[0] x = cm2u(point[0]) + self.left_margin y = self.top_margin - cm2u(point[1]) self.gpc.moveto(x,y) for point in path[1:]: x = cm2u(point[0]) + self.left_margin y = self.top_margin - cm2u(point[1]) self.gpc.lineto(x,y) self.gpc.closepath() self.gpc.setrgbcolor(color[0],color[1],color[2]) self.gpc.fill() self.gpc.setrgbcolor(0,0,0) def draw_box(self,style,text,x,y): #assuming that we start drawing box from current position self.brand_new_page = 0 x = self.left_margin + cm2u(x) y = self.top_margin - cm2u(y) box_style = self.draw_styles[style] para_name = box_style.get_paragraph_style() para_style = self.style_list[para_name] fontstyle = para_style.get_font() bh = cm2u(box_style.get_height()) bw = cm2u(box_style.get_width()) self.gpc.rect_stroked(x,y,bw,-bh) if text: lines = text.split('\n') start_x = x + 0.5 * fontstyle.get_size() start_y = y - fontstyle.get_size() * _EXTRA_SPACING_FACTOR for line in lines: if not line.split(): continue self.gpc.setfont(find_font_from_fontstyle(fontstyle)) self.gpc.moveto(start_x,start_y) self.gpc.show(line) start_y -= fontstyle.get_size() * _EXTRA_SPACING_FACTOR def write_at (self, style, text, x, y): self.brand_new_page = 0 para_style = self.style_list[style] fontstyle = para_style.get_font() self.gpc.setfont(find_font_from_fontstyle(fontstyle)) self.gpc.moveto(cm2u(x), cm2u(y)) self.gpc.show(text) def draw_bar(self, style, x1, y1, x2, y2): self.brand_new_page = 0 self.gpc.moveto(x1, y1) self.gpc.lineto(x2, y2) def draw_text(self,style,text,x,y): self.brand_new_page = 0 box_style = self.draw_styles[style] para_name = box_style.get_paragraph_style() para_style = self.style_list[para_name] fontstyle = para_style.get_font() start_x = self.left_margin + cm2u(x) start_y = self.top_margin - cm2u(y) - fontstyle.get_size() * _EXTRA_SPACING_FACTOR self.gpc.setfont(find_font_from_fontstyle(fontstyle)) self.gpc.moveto(start_x,start_y) self.gpc.show(text) def center_text(self,style,text,x,y): self.brand_new_page = 0 box_style = self.draw_styles[style] para_name = box_style.get_paragraph_style() para_style = self.style_list[para_name] fontstyle = para_style.get_font() width = get_text_width(text,fontstyle) start_x = self.left_margin + cm2u(x) - 0.5 * width start_y = self.top_margin - cm2u(y) \ - fontstyle.get_size() * _EXTRA_SPACING_FACTOR self.gpc.setfont(find_font_from_fontstyle(fontstyle)) self.gpc.moveto(start_x, start_y) self.gpc.show(text) def rotate_text(self,style,text,x,y,angle): self.brand_new_page = 0 # FIXME - remove when new gnome-python is in all distros if not support_photos: return # end FIXME box_style = self.draw_styles[style] para_name = box_style.get_paragraph_style() para_style = self.style_list[para_name] fontstyle = para_style.get_font() y_start = self.top_margin - cm2u(y) x_start = self.left_margin + cm2u(x) size = fontstyle.get_size() self.gpc.gsave() self.gpc.translate(x_start,y_start) self.gpc.rotate(-angle) this_y = 0 for line in text: if not line.split(): continue width = get_text_width(line,fontstyle) this_x = -0.5 * width self.gpc.setfont(find_font_from_fontstyle(fontstyle)) self.gpc.moveto(this_x,this_y) self.gpc.show(line) this_y -= size * _EXTRA_SPACING_FACTOR self.gpc.grestore() def draw_line(self,style,x1,y1,x2,y2): self.brand_new_page = 0 x1 = cm2u(x1) + self.left_margin x2 = cm2u(x2) + self.left_margin y1 = self.top_margin - cm2u(y1) y2 = self.top_margin - cm2u(y2) self.gpc.line_stroked(x1,y1,x2,y2) #------------------------------------------------------------------------ # # Print job methods # #------------------------------------------------------------------------ #function to print text to a printer def do_print(self,dialog,job): self.gpc = gnomeprint.Context(dialog.get_config()) job.render(self.gpc) self.gpc.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..."), gnomeprint.ui.DIALOG_RANGE|gnomeprint.ui.DIALOG_COPIES) dialog.construct_range_page( gnomeprint.ui.RANGE_ALL|gnomeprint.ui.RANGE_RANGE, 1, self.page_count, "A", "Pages: ") dialog.connect('response', self.print_dialog_response, self.job) dialog.show() #------------------------------------------------------------------------ # # Register the document generator with the system # #------------------------------------------------------------------------ PluginMgr.register_text_doc( name=_("Print..."), classref=LPRDoc, table=1, paper=1, style=1, ext="", print_report_label=None, clname='print') PluginMgr.register_book_doc( _("Print..."), LPRDoc, 1, 1, 1, "", 'print') PluginMgr.register_draw_doc( _("Print..."), LPRDoc, 1, 1, "", None, 'print')