Ignore:
Timestamp:
7 Apr 2012, 08:15:16 (12 years ago)
Author:
uli
Message:

Improve pdf generation: a global pdf generator, watermarks and more.

Location:
main/waeup.kofa/trunk/src/waeup/kofa
Files:
3 added
2 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/trunk/src/waeup/kofa/applicants/pdf.py

    r8050 r8059  
    2020"""
    2121import grok
    22 from datetime import datetime
    23 from reportlab.pdfgen import canvas
     22from reportlab.lib.styles import getSampleStyleSheet
    2423from reportlab.lib.units import cm
    25 from reportlab.lib.pagesizes import A4
    26 from reportlab.lib.styles import getSampleStyleSheet
    27 from reportlab.platypus import Frame, Paragraph, Image, Table, Spacer
    28 from reportlab.platypus.tables import TableStyle
    29 from zope.i18n import translate
     24from reportlab.platypus import Paragraph, Image, Table, Spacer
    3025from zope.component import getUtility
    3126from zope.formlib.form import setUpEditWidgets
     27from zope.i18n import translate
    3228from zope.publisher.browser import TestRequest
    33 from waeup.kofa.widgets.datewidget import FriendlyDateDisplayWidget
    3429from waeup.kofa.applicants.interfaces import IApplicant, IApplicantsUtils
    3530from waeup.kofa.browser import DEFAULT_PASSPORT_IMAGE_PATH
     31from waeup.kofa.browser.interfaces import IPDFCreator
    3632from waeup.kofa.interfaces import IExtFileStore, IPDF, IKofaUtils
    3733from waeup.kofa.interfaces import MessageFactory as _
    38 
    39 SLIP_STYLE = TableStyle(
    40     [('VALIGN',(0,0),(-1,-1),'TOP')]
    41     )
    42 
     34from waeup.kofa.widgets.datewidget import FriendlyDateDisplayWidget
    4335
    4436class PDFApplicationSlip(grok.Adapter):
    45 
     37    """Create a PDF application slip for applicants.
     38    """
     39    # XXX: Many things in here are reusable. We might want to split
     40    # things. Possibly move parts to IPDFCreator?
    4641    grok.context(IApplicant)
    4742    grok.implements(IPDF)
     
    129124        return data
    130125
    131     def __call__(self, view=None):
    132         """Return a PDF representation of the context applicant.
    133 
    134         If no `view` is given, the course admitted field will be an
    135         empty string and author will be set as ``'unknown'``.
    136 
    137         If a `view` is given, author will be set as the calling
    138         principal.
    139         """
    140         pdf = canvas.Canvas('application_slip.pdf',pagesize=A4)
    141         pdf.setTitle(self.title)
    142         pdf.setSubject('Application')
    143         if view is None:
    144             pdf.setAuthor('unknown')
    145         if view is not None:
    146             pdf.setAuthor('%s (%s)' % (view.request.principal.title,
    147                 view.request.principal.id))
    148         pdf.setCreator('Kofa')
    149         width, height = A4
    150         style = getSampleStyleSheet()
    151         pdf.line(1*cm,height-(1.8*cm),width-(1*cm),height-(1.8*cm))
    152 
    153         story = []
    154         frame_header = Frame(1*cm,1*cm,width-(1.7*cm),height-(1.7*cm))
    155         header_title = getattr(grok.getSite(), 'name', u'Sample University')
    156         story.append(Paragraph(header_title, style["Heading1"]))
    157         frame_header.addFromList(story,pdf)
    158 
    159         story = []
    160         frame_body = Frame(1*cm,1*cm,width-(2*cm),height-(3.5*cm))
    161         story.append(Paragraph(self.title, style["Heading2"]))
    162         story.append(Spacer(1, 18))
    163         for msg in self.context.history.messages:
    164             f_msg = '<font face="Courier" size=10>%s</font>' % msg
    165             story.append(Paragraph(f_msg, style["Normal"]))
    166         story.append(Spacer(1, 24))
    167 
    168         # Setup table data
    169         data = []
    170         # Insert passport photograph
    171         data = self._addPassportImage(data)
    172         # Render widget fields
     126    def _getWidgetsTable(self, view):
     127        """Return a reportlab table buildt of widgets.
     128        """
     129        style = getSampleStyleSheet()
     130        table_data = []
     131        table_style = [('LEFTPADDING', (0,0), (0,-1), 0),
     132                       ('VALIGN', (0,0), (-1,-1), 'TOP'),
     133                       ]
     134        row_num = 0
    173135        widgets = self._setUpWidgets()
    174136        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
    175         for widget in widgets: # self.widgets:
     137        for widget in widgets:
    176138            separators = getUtility(IApplicantsUtils).SEPARATORS_DICT
    177139            if separators and separators.get(widget.name):
     
    180142                    target_language=portal_language))
    181143                f_headline = Paragraph(f_headline, style["Normal"])
    182                 data.append([f_headline ])
     144                table_data.append([f_headline ])
     145                table_style.append(('SPAN', (0,row_num), (-1,row_num)),)
     146                table_style.append(
     147                    ('TOPPADDING', (0,row_num), (-1,row_num), 12),)
     148                row_num += 1
    183149            f_label = '<font size=12>%s</font>:' % translate(
    184150                widget.label.strip(), 'waeup.kofa',
     
    191157            f_text = f_text.replace('\n', '')
    192158            f_text = Paragraph(f_text, style["Normal"])
    193             data.append([f_label,f_text])
     159            table_data.append([f_label,f_text])
     160            row_num += 1
    194161        adm_translation = translate(_('Admitted Course of Study:'),
    195162                'waeup.kofa', target_language=portal_language)
     
    199166        f_label = Paragraph(f_label, style["Normal"])
    200167        f_text = Paragraph(f_text, style["Normal"])
    201         data.append([f_label,f_text])
     168        table_data.append([f_label,f_text])
     169        row_num += 1
    202170
    203171        # Add dept. and faculty if applicable
    204         data = self._addDeptAndFaculty(data)
     172        table_data = self._addDeptAndFaculty(table_data)
    205173
    206174        # Create table
    207         table = Table(data,style=SLIP_STYLE, colWidths=[10*cm, 8.5*cm])
    208         story.append(table)
    209 
    210         # Add some comments
     175        table = Table(table_data,style=table_style)
     176        table.hAlign = 'LEFT'
     177        return table
     178
     179    def _addComments(self, data):
     180        style = getSampleStyleSheet()
    211181        if self.context.state == 'created':
    212182            comment1 = _(
     
    214184                ' and enter your new credentials:' +
    215185                ' user name= ${a}, password = ${b}.</font>', mapping = {
    216                 'a':self.context.student_id, 'b':self.context.application_number}
     186                    'a':self.context.student_id,
     187                    'b':self.context.application_number}
    217188                )
    218189            comment2 = _(
     
    222193            comment1 = Paragraph(comment1, style["Normal"])
    223194            comment2 = Paragraph(comment2, style["Normal"])
    224             story.append(Spacer(1, 18))
    225             story.append(comment1)
    226             story.append(comment2)
    227 
    228         frame_body.addFromList(story,pdf)
    229 
    230         story = []
    231         frame_footer = Frame(1*cm,0,width-(2*cm),1*cm)
    232         timestamp = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
    233         f_text = '<font size=10>%s</font>' % timestamp
    234         story.append(Paragraph(f_text, style["Normal"]))
    235         frame_footer.addFromList(story,pdf)
    236         return pdf.getpdfdata()
     195            data.extend([Spacer(1, 18), comment1, comment2])
     196        return data
     197
     198    def __call__(self, view=None):
     199        """Return a PDF representation of the context applicant.
     200
     201        If no `view` is given, the course admitted field will be an
     202        empty string and author will be set as ``'unknown'``.
     203
     204        If a `view` is given, author will be set as the calling
     205        principal.
     206        """
     207        doc_title = self.title.replace('-', '\n')
     208        style = getSampleStyleSheet()
     209        data = []
     210
     211        # append history
     212        for msg in self.context.history.messages:
     213            f_msg = '<font face="Courier" size=10>%s</font>' % msg
     214            data.append(Paragraph(f_msg, style["Normal"]))
     215        data.append(Spacer(1, 20))
     216
     217        # append photograph
     218        img_path = getattr(
     219            getUtility(IExtFileStore).getFileByContext(self.context),
     220            'name', DEFAULT_PASSPORT_IMAGE_PATH)
     221        doc_img = Image(img_path, width=4*cm, height=3*cm, kind='bound')
     222        doc_img.hAlign='LEFT'
     223        data.append(doc_img)
     224
     225        # append widgets
     226        data.append(self._getWidgetsTable(view))
     227
     228        # append comments
     229        data = self._addComments(data)
     230
     231        creator = getUtility(IPDFCreator)
     232        return creator.create_pdf(data, None, doc_title)
  • main/waeup.kofa/trunk/src/waeup/kofa/browser/interfaces.py

    r7819 r8059  
    163163        """Get captcha chosen for a certain site or default.
    164164        """
     165
     166class IPDFCreator(Interface):
     167    """A component that knows where logo graphics for PDFs are stored
     168    and can generate PDF documents.
     169
     170    It is a utility (and not a simple function or class) to make these
     171    data customizable in derived packages.
     172    """
     173    header_logo_path = schema.TextLine(
     174        title = u'Path to header logo JPG')
     175    watermark_path = schema.TextLine(
     176        title = u'Path to watermark logo JPG')
     177    def paint_background(canvas, doc):
     178        """A callback function to render background of PDFs.
     179        """
     180    def create_pdf(data, headerline=None, title=None):
     181        """Create a PDF.
     182
     183        `data` is expected to be a list of reportlab flowables
     184        (paragraphs, images, tables, etc.), that will be rendered into
     185        some background.
     186
     187        `headerline` will be displayed in page head and `title` under
     188        the top bar.
     189
     190        If no `headerline` is given, a default will be rendered (name
     191        of university).
     192
     193        If no `title` is given, nothing will be rendered.
     194        """
Note: See TracChangeset for help on using the changeset viewer.