Add initial stab at GtkPrint.
svn: r7869
This commit is contained in:
		@@ -1,3 +1,6 @@
 | 
			
		||||
2007-01-05 Richard Taylor  <rjt-gramps@thegrindstone.me.uk>
 | 
			
		||||
	* src/docgen/GtkPrint.py: Add initial stab at GtkPrint.
 | 
			
		||||
	
 | 
			
		||||
2007-01-04  Zsolt Foldvari  <zfoldvar@users.sourceforge.net>
 | 
			
		||||
	* src/GrampsWidgets.py: Add ValidatableMaskedEntry what extends
 | 
			
		||||
	the MaskedEntry with validation feature
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										413
									
								
								gramps2/src/docgen/GtkPrint.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										413
									
								
								gramps2/src/docgen/GtkPrint.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,413 @@
 | 
			
		||||
#
 | 
			
		||||
# Gramps - a GTK+/GNOME based genealogy program
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2000-2006  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
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
# $Id: PdfDoc.py 7855 2006-12-29 03:58:26Z dallingham $
 | 
			
		||||
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
#
 | 
			
		||||
# Python modules
 | 
			
		||||
#
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
from gettext import gettext as _
 | 
			
		||||
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
#
 | 
			
		||||
# gramps modules
 | 
			
		||||
#
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
import BaseDoc
 | 
			
		||||
from PluginUtils import register_text_doc, register_draw_doc, register_book_doc
 | 
			
		||||
import Errors
 | 
			
		||||
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
#
 | 
			
		||||
# Set up logging
 | 
			
		||||
#
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
import logging
 | 
			
		||||
log = logging.getLogger(".GtkDoc")
 | 
			
		||||
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
#
 | 
			
		||||
# GtkPrint 
 | 
			
		||||
#
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
import pygtk
 | 
			
		||||
import gtk
 | 
			
		||||
import cairo
 | 
			
		||||
import pango
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
#
 | 
			
		||||
# PreviewCanvas and PreviewWindow
 | 
			
		||||
#
 | 
			
		||||
# These classes provide a simple print preview functionality.
 | 
			
		||||
# They do not actually render anything themselves, they rely
 | 
			
		||||
# upon the Print opertaion to do the rendering.
 | 
			
		||||
#
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
class PreviewCanvas(gtk.DrawingArea):
 | 
			
		||||
    """This provides a simple widget for displaying a
 | 
			
		||||
    cairo rendering used to show print preview windows.
 | 
			
		||||
    """
 | 
			
		||||
    
 | 
			
		||||
    def __init__(self,
 | 
			
		||||
                 operation,
 | 
			
		||||
                 preview_operation,
 | 
			
		||||
                 print_context):
 | 
			
		||||
        gtk.DrawingArea.__init__(self)
 | 
			
		||||
        self._operation = operation
 | 
			
		||||
        self._preview_operation = preview_operation
 | 
			
		||||
        self._print_context = print_context
 | 
			
		||||
 | 
			
		||||
        self.connect("expose_event",self.expose)
 | 
			
		||||
        
 | 
			
		||||
        self._page_no = 1 # always start on page 1
 | 
			
		||||
 | 
			
		||||
        self.set_size_request(200, 300)
 | 
			
		||||
 | 
			
		||||
    def set_page(self,page):
 | 
			
		||||
        """Change which page is displayed"""
 | 
			
		||||
        if page > 0:
 | 
			
		||||
            self._page_no = page
 | 
			
		||||
            self.queue_draw()
 | 
			
		||||
        
 | 
			
		||||
    def realize(self):
 | 
			
		||||
        """Generate the cairo context for this drawing area
 | 
			
		||||
        and pass it to the print context."""
 | 
			
		||||
        gtk.DrawingArea.realize(self)
 | 
			
		||||
        self._context = self.window.cairo_create()
 | 
			
		||||
        self._print_context.set_cairo_context(self._context,72,72)
 | 
			
		||||
 | 
			
		||||
    def expose(self, widget, event):
 | 
			
		||||
        """Ask the print operation to actually draw the page."""
 | 
			
		||||
        print "expose"
 | 
			
		||||
        self.window.clear()
 | 
			
		||||
        self._preview_operation.render_page(self._page_no)
 | 
			
		||||
    
 | 
			
		||||
class PreviewWindow(gtk.Window):
 | 
			
		||||
    """A dialog to show a print preview."""
 | 
			
		||||
    
 | 
			
		||||
    def __init__(self,
 | 
			
		||||
                 operation,
 | 
			
		||||
                 preview_operation,
 | 
			
		||||
                 print_context,
 | 
			
		||||
                 parent):
 | 
			
		||||
        gtk.Window.__init__(self)
 | 
			
		||||
        
 | 
			
		||||
        self._operation = operation
 | 
			
		||||
        self._preview_operation = preview_operation
 | 
			
		||||
 | 
			
		||||
        self.connect("delete_event", self.delete_event)
 | 
			
		||||
 | 
			
		||||
        self.set_title("Print Preview")
 | 
			
		||||
        self.set_transient_for(parent)
 | 
			
		||||
 | 
			
		||||
        # Setup widgets
 | 
			
		||||
        self._vbox = gtk.VBox()
 | 
			
		||||
        self.add(self._vbox)
 | 
			
		||||
        self._spin = gtk.SpinButton()
 | 
			
		||||
        self._spin.set_value(1)
 | 
			
		||||
        
 | 
			
		||||
        self._close_bt = gtk.Button(stock=gtk.STOCK_CLOSE)
 | 
			
		||||
        self._close_bt.connect("clicked",self.close)
 | 
			
		||||
                               
 | 
			
		||||
        self._hbox = gtk.HBox()
 | 
			
		||||
        self._hbox.pack_start(self._spin)
 | 
			
		||||
        self._hbox.pack_start(self._close_bt,expand=False)
 | 
			
		||||
        self._vbox.pack_start(self._hbox,expand=False)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        self._scroll = gtk.ScrolledWindow(None,None)
 | 
			
		||||
        self._canvas = PreviewCanvas(operation,preview_operation,print_context)
 | 
			
		||||
        self._scroll.add_with_viewport(self._canvas)
 | 
			
		||||
        self._vbox.pack_start(self._scroll,expand=True,fill=True)
 | 
			
		||||
 | 
			
		||||
        # The print operation does not know how many pages there are until
 | 
			
		||||
        # after the first expose event, so we use the expose event to
 | 
			
		||||
        # trigger an update of the spin box.
 | 
			
		||||
        # This still does not work properly, sometimes the first expose event
 | 
			
		||||
        # happends before this gets connected and the spin box does not get
 | 
			
		||||
        # updated, I am probably just not doing it very cleverly.
 | 
			
		||||
        self._change_n_pages_connect_id = self._canvas.connect("expose_event", self.change_n_pages)
 | 
			
		||||
        self._spin.connect("value-changed",
 | 
			
		||||
                           lambda spinbutton: self._canvas.set_page(spinbutton.get_value_as_int()))
 | 
			
		||||
        
 | 
			
		||||
        self._canvas.set_double_buffered(False)
 | 
			
		||||
        self._canvas.realize()
 | 
			
		||||
 | 
			
		||||
        self.show_all()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def change_n_pages(self, widget, event ):
 | 
			
		||||
        """Update the spin box to have the correct number of pages for the
 | 
			
		||||
        print operation"""
 | 
			
		||||
        n_pages = self._preview_operation.get_property("n_pages")
 | 
			
		||||
        
 | 
			
		||||
        if n_pages != -1:
 | 
			
		||||
            # As soon as we have a valid number of pages we no
 | 
			
		||||
            # longer need this call back so we can disconnect it.
 | 
			
		||||
            self._canvas.disconnect(self._change_n_pages_connect_id)
 | 
			
		||||
            
 | 
			
		||||
        value = int(self._spin.get_value())
 | 
			
		||||
        if value == -1: value = 1
 | 
			
		||||
        self._spin.configure(gtk.Adjustment(value,1,
 | 
			
		||||
                                            n_pages,
 | 
			
		||||
                                            1,1,1),1,0)
 | 
			
		||||
 | 
			
		||||
    def end_preview(self):
 | 
			
		||||
        self._operation.end_preview()
 | 
			
		||||
        
 | 
			
		||||
    def delete_event(self, widget, event, data=None):
 | 
			
		||||
        self.end_preview()
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    def close(self,btn):
 | 
			
		||||
        self.end_preview()
 | 
			
		||||
        self.destroy()
 | 
			
		||||
 | 
			
		||||
        # I am not sure that this is the correct way to do this
 | 
			
		||||
        # but I expect the print dialog to reappear after I
 | 
			
		||||
        # close the print preview button.
 | 
			
		||||
        self._operation.do_print()
 | 
			
		||||
        return False       
 | 
			
		||||
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
#
 | 
			
		||||
# 
 | 
			
		||||
#
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
class PrintFacade(gtk.PrintOperation):
 | 
			
		||||
    """Provides the main print operation functions."""
 | 
			
		||||
    
 | 
			
		||||
    def __init__(self, renderer):
 | 
			
		||||
        """
 | 
			
		||||
        render must be an object with the following interface:
 | 
			
		||||
           render: callable that takes (operation, context, page_nr)
 | 
			
		||||
                   it should render the page_nr page onto the provided context.
 | 
			
		||||
           get_n_pages: a callable that takes (operation, context) and
 | 
			
		||||
                        returns the number of pages that would be needed to render
 | 
			
		||||
                        onto the given context.
 | 
			
		||||
        """
 | 
			
		||||
        gtk.PrintOperation.__init__(self)
 | 
			
		||||
 | 
			
		||||
        self._renderer = renderer
 | 
			
		||||
        
 | 
			
		||||
        self.connect("begin_print", self.begin_print)
 | 
			
		||||
        self.connect("draw_page", self.draw_page)
 | 
			
		||||
        self.connect("paginate", self.paginate)
 | 
			
		||||
        self.connect("preview", self.preview)        
 | 
			
		||||
 | 
			
		||||
        self._settings = None
 | 
			
		||||
        self._print_op = None
 | 
			
		||||
        
 | 
			
		||||
    def begin_print(self,operation, context):
 | 
			
		||||
        operation.set_n_pages(self._renderer.get_n_pages(operation, context))
 | 
			
		||||
 | 
			
		||||
    def paginate(self, operation, context):
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def preview(self, preview, preview_again, context, parent, dummy=None):
 | 
			
		||||
        # It looks like there is a bug in the pygtk bindings that
 | 
			
		||||
        # passes the preview_opertion in twice.
 | 
			
		||||
 | 
			
		||||
        preview = PreviewWindow(self,preview,context,parent)
 | 
			
		||||
        return True
 | 
			
		||||
        
 | 
			
		||||
    def draw_page(self,operation, context, page_nr):
 | 
			
		||||
        self._renderer.render(operation, context, page_nr)
 | 
			
		||||
        
 | 
			
		||||
    def do_print(self, widget=None, data=None):
 | 
			
		||||
        """This is the method that actually runs the Gtk Print operation."""
 | 
			
		||||
 | 
			
		||||
        # We need to store the settings somewhere so that they are remembered
 | 
			
		||||
        # each to the dialog is restarted.
 | 
			
		||||
        if self._settings != None:
 | 
			
		||||
            self.set_print_settings(self._settings)
 | 
			
		||||
 | 
			
		||||
        res = self.run(gtk.PRINT_OPERATION_ACTION_PRINT_DIALOG, None)
 | 
			
		||||
        
 | 
			
		||||
        if res == gtk.PRINT_OPERATION_RESULT_APPLY:
 | 
			
		||||
            self._settings = self.get_print_settings()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
#
 | 
			
		||||
# CairoJob and GtkDoc
 | 
			
		||||
#
 | 
			
		||||
# These classes to the real work. GtkDoc provides the BaseDoc interface
 | 
			
		||||
# and CairoJob performs the job that gnomeprintjob does. It has to
 | 
			
		||||
# maintain an abstract model of the document and then render it onto
 | 
			
		||||
# a cairo context when asked.
 | 
			
		||||
#
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
class CairoJob(object):
 | 
			
		||||
    """Class to act as a abstract document that can render onto a
 | 
			
		||||
    cairo context."""
 | 
			
		||||
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        self._doc = []
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # interface required for PrintFacade
 | 
			
		||||
    #
 | 
			
		||||
    def render(self, operation, context, page_nr):
 | 
			
		||||
        cr = context.get_cairo_context()
 | 
			
		||||
 | 
			
		||||
        y = 20
 | 
			
		||||
        x = 30
 | 
			
		||||
 | 
			
		||||
        print "self._doc: ", 
 | 
			
		||||
        text="\n".join(self._doc)
 | 
			
		||||
        
 | 
			
		||||
        # Draw some text
 | 
			
		||||
        layout = context.create_pango_layout()
 | 
			
		||||
        layout.set_text(text)
 | 
			
		||||
        desc = pango.FontDescription("sans 28")
 | 
			
		||||
        layout.set_font_description(desc)
 | 
			
		||||
 | 
			
		||||
        cr.move_to(x, y)
 | 
			
		||||
        cr.show_layout(layout)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def get_n_pages(self, operation, context):
 | 
			
		||||
        """return the number of pages required to print onto the
 | 
			
		||||
        provided context."""
 | 
			
		||||
 | 
			
		||||
        return 3
 | 
			
		||||
    
 | 
			
		||||
    #
 | 
			
		||||
    # methods to add context to abstract document.
 | 
			
		||||
    #
 | 
			
		||||
 | 
			
		||||
    def write_text(self,text):
 | 
			
		||||
        self._doc.append(text)
 | 
			
		||||
        
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
#
 | 
			
		||||
# 
 | 
			
		||||
#
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
class GtkDoc(BaseDoc.BaseDoc):
 | 
			
		||||
 | 
			
		||||
    def open(self,filename):
 | 
			
		||||
        self._job = CairoJob()
 | 
			
		||||
    
 | 
			
		||||
    def close(self):
 | 
			
		||||
        PrintFacade(self._job).do_print()
 | 
			
		||||
        
 | 
			
		||||
    def page_break(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def start_paragraph(self,style_name,leader=None):
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
    def end_paragraph(self):
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
    def start_bold(self):
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
    def end_bold(self):
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
    def start_superscript(self):
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
    def end_superscript(self):
 | 
			
		||||
        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_media_object(self,name,pos,x_cm,y_cm):
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
    def write_note(self,text,format,style_name):
 | 
			
		||||
        print "write_note: ", text
 | 
			
		||||
        self._job.write_text(text)
 | 
			
		||||
    
 | 
			
		||||
    def write_text(self,text,mark=None):
 | 
			
		||||
        print "write_text: ", text
 | 
			
		||||
        self._job.write_text(text)
 | 
			
		||||
    
 | 
			
		||||
    def start_page(self):
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
    def end_page(self):
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
    def draw_line(self,style,x1,y1,x2,y2):
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
    def write_at(self, style, text, x, y):
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
    def draw_bar(self, style, x1, y1, x2, y2):
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
    def draw_path(self,style,path):
 | 
			
		||||
        pass
 | 
			
		||||
        
 | 
			
		||||
    def draw_box(self,style,text,x,y):
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
    def draw_text(self,style,text,x,y):
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
    def rotate_text(self,style,text,x,y,angle):
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
    def center_text(self,style,text,x,y):
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
    def center_print(self,lines,font,x,y,w,h):
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
    def left_print(self,lines,font,x,y):
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
#
 | 
			
		||||
# Register the document generator with the GRAMPS plugin system
 | 
			
		||||
#
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
register_text_doc(_('GtkPrint'), GtkDoc,1, 1, 1,"", None)
 | 
			
		||||
register_draw_doc(_('GtkPrint'), GtkDoc,1, 1,   "", None)
 | 
			
		||||
register_book_doc(name=_("GtkPrint"),classref=GtkDoc,
 | 
			
		||||
                  table=1,paper=1,style=1,ext="")
 | 
			
		||||
		Reference in New Issue
	
	Block a user