Index: /main/waeup.sirp/trunk/src/waeup/sirp/applicants/pdf.py
===================================================================
--- /main/waeup.sirp/trunk/src/waeup/sirp/applicants/pdf.py	(revision 7390)
+++ /main/waeup.sirp/trunk/src/waeup/sirp/applicants/pdf.py	(revision 7390)
@@ -0,0 +1,194 @@
+##
+## pdf.py
+## Login : <uli@pu.smp.net>
+## Started on  Mon Dec 19 09:30:43 2011 Uli Fouquet
+## $Id$
+## 
+## Copyright (C) 2011 Uli Fouquet
+## 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
+##
+"""
+Generate PDF docs for applicants.
+"""
+import grok
+from datetime import datetime
+from reportlab.pdfgen import canvas
+from reportlab.lib.units import cm
+from reportlab.lib.pagesizes import A4
+from reportlab.lib.styles import getSampleStyleSheet
+from reportlab.platypus import Frame, Paragraph, Image, Table, Spacer
+from reportlab.platypus.tables import TableStyle
+from zope.component import getUtility
+from zope.formlib.form import setUpEditWidgets
+from zope.interface import Interface
+from zope.publisher.browser import TestRequest
+from waeup.sirp.applicants.interfaces import IApplicant
+from waeup.sirp.browser import DEFAULT_PASSPORT_IMAGE_PATH
+from waeup.sirp.interfaces import IExtFileStore, IPDF
+
+SLIP_STYLE = TableStyle(
+    [('VALIGN',(0,0),(-1,-1),'TOP')]
+    )
+
+
+class PDFApplicationSlip(grok.Adapter):
+
+    grok.context(IApplicant)
+    grok.implements(IPDF)
+    grok.name('application_slip')
+
+    form_fields =  grok.AutoFields(IApplicant).omit(
+        'locked', 'course_admitted')
+
+    @property
+    def title(self):
+        container_title = self.context.__parent__.title
+        return '%s Application Record %s' % (
+            container_title, self.context.application_number)
+
+    def _setUpWidgets(self):
+        """Setup simple display widgets.
+
+        Returns the list of widgets.
+        """
+        request = TestRequest()
+        return setUpEditWidgets(
+            self.form_fields, 'form', self.context, request, {},
+            for_display=True, ignore_request=True
+            )
+
+    def _getCourseAdmittedLink(self, view):
+        """Return link, title and code in html format to the certificate
+           admitted.
+        """
+        course_admitted = self.context.course_admitted
+        if view is not None and getattr(course_admitted, '__parent__',None):
+            url = view.url(course_admitted)
+            title = course_admitted.title
+            code = course_admitted.code
+            return '<a href="%s">%s - %s</a>' %(url,code,title)
+        return ''
+
+    def _addPassportImage(self, data):
+        """Add passport image to data stream.
+
+        If no image exists yet the default image is added.
+        """
+        img = getUtility(IExtFileStore).getFileByContext(self.context)
+        if img is None:
+            img = open(DEFAULT_PASSPORT_IMAGE_PATH, 'rb')
+        doc_img = Image(img.name, width=4*cm, height=3*cm, kind='bound')
+        data.append([doc_img])
+        data.append([Spacer(1, 18)])
+        return data
+
+    def _addDeptAndFaculty(self, data):
+        """If we have a valid course admitted, add dept. and faculty to data
+           stream.
+        """
+        style = getSampleStyleSheet()
+        course_admitted = self.context.course_admitted
+        dept = getattr(
+                getattr(course_admitted, '__parent__', None),
+                '__parent__', None)
+        if dept is None:
+            return data
+        f_label = '<font size=12>Department:</font>'
+        f_text = '<font size=12>%s</font>' % dept.longtitle()
+        f_label = Paragraph(f_label, style["Normal"])
+        f_text = Paragraph(f_text, style["Normal"])
+        data.append([f_label,f_text])
+
+        faculty = getattr(dept, '__parent__', None)
+        if faculty is None:
+            return data
+        f_label = '<font size=12>Faculty:</font>'
+        f_text = '<font size=12>%s</font>' % faculty.longtitle()
+        f_label = Paragraph(f_label, style["Normal"])
+        f_text = Paragraph(f_text, style["Normal"])
+        data.append([f_label,f_text])
+        return data
+
+    def __call__(self, view=None):
+        """Return a PDF representation of the context applicant.
+
+        If no `view` is given, the course admitted field will be an
+        empty string and author will be set as ``'unknown'``.
+
+        If a `view` is given, author will be set as the calling
+        principal.
+        """
+        pdf = canvas.Canvas('application_slip.pdf',pagesize=A4)
+        pdf.setTitle(self.title)
+        pdf.setSubject('Application')
+        if view is None:
+            pdf.setAuthor('unknown')
+        if view is not None:
+            pdf.setAuthor('%s (%s)' % (view.request.principal.title,
+                                      view.request.principal.id))
+        pdf.setCreator('SIRP')
+        width, height = A4
+        style = getSampleStyleSheet()
+        pdf.line(1*cm,height-(1.8*cm),width-(1*cm),height-(1.8*cm))
+
+        story = []
+        frame_header = Frame(1*cm,1*cm,width-(1.7*cm),height-(1.7*cm))
+        header_title = getattr(grok.getSite(), 'name', u'Sample University')
+        story.append(Paragraph(header_title, style["Heading1"]))
+        frame_header.addFromList(story,pdf)
+
+        story = []
+        frame_body = Frame(1*cm,1*cm,width-(2*cm),height-(3.5*cm))
+        story.append(Paragraph(self.title, style["Heading2"]))
+        story.append(Spacer(1, 18))
+        for msg in self.context.history.messages:
+            f_msg = '<font face="Courier" size=10>%s</font>' % msg
+            story.append(Paragraph(f_msg, style["Normal"]))
+        story.append(Spacer(1, 24))
+
+        # Setup table data
+        data = []
+        # Insert passport photograph
+        data = self._addPassportImage(data)
+        # Render widget fields
+        widgets = self._setUpWidgets()
+        for widget in widgets: # self.widgets:
+            f_label = '<font size=12>%s</font>:' % widget.label.strip()
+            f_label = Paragraph(f_label, style["Normal"])
+            f_text = '<font size=12>%s</font>' % widget()
+            f_text = Paragraph(f_text, style["Normal"])
+            data.append([f_label,f_text])
+        f_label = '<font size=12>Admitted Course of Study:</font>'
+        f_text = '<font size=12>%s</font>' % (
+            self._getCourseAdmittedLink(view),)
+        f_label = Paragraph(f_label, style["Normal"])
+        f_text = Paragraph(f_text, style["Normal"])
+        data.append([f_label,f_text])
+
+        # Add dept. and faculty if applicable
+        data = self._addDeptAndFaculty(data)
+
+        # Create table
+        table = Table(data,style=SLIP_STYLE)
+        story.append(table)
+        frame_body.addFromList(story,pdf)
+
+        story = []
+        frame_footer = Frame(1*cm,0,width-(2*cm),1*cm)
+        timestamp = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
+        f_text = '<font size=10>%s</font>' % timestamp
+        story.append(Paragraph(f_text, style["Normal"]))
+        frame_footer.addFromList(story,pdf)
+        return pdf.getpdfdata()
