--- a/svv/wsgi.py Mon Dec 20 01:02:56 2010 +0200
+++ b/svv/wsgi.py Mon Dec 20 20:51:45 2010 +0200
@@ -1,9 +1,17 @@
+# coding: utf-8
+
+"""
+ WSGI frontend/entry point
+"""
+
import werkzeug
from werkzeug import exceptions
from werkzeug import Request, Response
from werkzeug.routing import Map, Rule
import logging
+
+import datetime
# logging
log = logging.getLogger('svv.wsgi')
@@ -100,23 +108,308 @@
def respond (self, url_values) :
from reportlab import platypus as rlpp
from reportlab.lib.units import inch
- from reportlab.lib.styles import getSampleStyleSheet
+ from reportlab.lib import pagesizes, styles
from cStringIO import StringIO
+ import itertools
buf = StringIO()
- styles = getSampleStyleSheet()
- style = styles['Normal']
+
+ # dimensions
+ page_width, page_height = page_size = pagesizes.A4
+ header_height = 1 * inch
+ footer_height = 1 * inch
+
+ margin = inch
+ frame_width = page_width - 2 * margin
+ frame_height = page_height - footer_height - margin / 2 - margin / 2 - header_height
+ frame_bottom = footer_height + margin / 2
+ frame_left = margin
+ frame = rlpp.Frame(frame_left, frame_bottom, frame_width, frame_height)
title = url_values.get('name', "Hello World")
- tpl = rlpp.PageTemplate('test', [ rlpp.Frame(inch, inch, 6 * inch, 9 * inch) ])
- doc = rlpp.BaseDocTemplate(buf, pageTemplates=[tpl], title=title, author="Test Author", showBoundary=True)
+ def draw_page_tpl (canvas, document) :
+ cols = 4
+ col_width = (page_width - 2 * margin) / 4
+
+ def draw_column (x, y, title, lines, gray=None) :
+ text = canvas.beginText(x, y)
+
+ if gray:
+ text.setFillGray(gray)
+
+ # title + rest
+ text.setFont("Times-Bold", 8)
+ text.textLine(title)
+ text.setFont("Times-Roman", 8)
+ text.textLines(lines)
+
+ canvas.drawText(text)
+
+
+ #
+ # header
+ #
+ x = margin
+ y = page_height - margin / 4
+
+ # spacer
+ y = page_height - footer_height
+
+ canvas.setLineWidth(0.5)
+ canvas.line(x - margin / 2, y, page_width - margin / 2, y)
+
+ # columns
+ x = margin + 3 * col_width
+ y = page_height - margin / 4
+
+ today = datetime.date.today()
+
+ draw_column(x, y - inch / 6, "Vuokrasopimus", str("%(title)s\n%(today)s" % dict(
+ today = today.strftime("%d / %m / %Y"),
+ title = title
+ ))),
+
+
+ #
+ # footer
+ #
+ x = margin
+ y = footer_height
+
+ # spacer
+ canvas.setLineWidth(0.5)
+ canvas.line(x - margin / 2, y, page_width - margin / 2, y)
+
+ # column
+ draw_column(x, y - inch / 6, "Teekkarispeksi Ry", "www.teekkarispeksi.fi", 0.4)
+ x += col_width
+
+ draw_column(x, y - inch / 6, "Tekniikkavastaava", "Juha Kallas\n045 xxx yyzz\njskallas@cc.hut.fi", 0.4)
+ x += col_width
+
+ draw_column(x, y - inch / 6, "Varastovastaava", "Joel Pirttimaa\n045 xxx yyzz\njhpirtti@cc.hut.fi", 0.4)
+ x += col_width
+
+ tpl = rlpp.PageTemplate('page', [frame], onPage=draw_page_tpl, pagesize=page_size)
+ doc = rlpp.BaseDocTemplate(buf, pageTemplates=[tpl], title=title, author="Test Author", showBoundary=False, pageSize=page_size)
+
+ samplestyles = styles.getSampleStyleSheet()
+
+ # normal text
+ h1 = styles.ParagraphStyle('Heading1', samplestyles['h1'],
+ fontName = 'Times-Bold',
+ fontSize = 22,
+ spaceBefore = 0,
+ spaceAfter = 0,
+
+ )
+
+ h2 = styles.ParagraphStyle('Heading2', samplestyles['h2'],
+ fontName = 'Times-Bold',
+ fontSize = 14,
+ spaceBefore = 6,
+ spaceAfter = 0,
+ )
+
+ h3 = styles.ParagraphStyle('Heading3', samplestyles['h3'],
+ fontName = 'Times-Italic',
+ fontSize = 12,
+ spaceBefore = 0,
+ spaceAfter = 0,
+ )
+
+ text = styles.ParagraphStyle('Text', samplestyles['Normal'],
+
+ )
+
+ # standard indent
+ list_indent = inch / 4
+
+ # root title
+ list_h1 = styles.ParagraphStyle('ListHeading1', samplestyles['h1'],
+ bulletIndent = 0,
+ leftIndent = 0,
+ )
+
+ # section
+ list_h2 = styles.ParagraphStyle('ListHeading2', samplestyles['h2'],
+ bulletIndent = 0,
+ leftIndent = list_indent,
+ fontName = 'Times-Bold',
+ fontSize = 10,
+ leading = 12,
+ spaceBefore = 6,
+ spaceAfter = 0,
+ )
+
+ # segment
+ list_h3 = styles.ParagraphStyle('ListHeading3', samplestyles['h3'],
+ bulletIndent = 0,
+ leftIndent = list_indent,
+ fontName = 'Times-Italic',
+ fontSize = 10,
+ leading = 12,
+ spaceBefore = 0,
+ spaceAfter = 0,
+ )
+
+ list_text = styles.ParagraphStyle('ListText', samplestyles['Normal'],
+ bulletIndent = 0,
+ leftIndent = list_indent,
+ )
+
+ def tree_seq () :
+ """
+ Tree list numbering
+ """
+
+ for idx in itertools.count(1) :
+ yield "%d." % (idx, )
+
+ # tree root
+ tree = ("Sopimusehdot", h2, None, tree_seq(), [
+ ("Osapuolet", list_h2, None, tree_seq(), [
+ (None, None, "Teekkarispeksi ry (Y-tunnus 1888541-7), jäljempänä “Vuokranantaja”."),
+ (None, None, title + u", jäljempänä “Vuokraaja”. 1.1 ja 1.2 jäljempänä yhdessä “osapuolet”.")
+ ]),
+ ("Kaluston lainaaminen", list_h2, None, tree_seq(), [
+ ("Yleistä", list_h3, "Tässä sopimuksessa sovitaan toiminnasta Vuokranantajan lainatessa tanssimattoja Vuokraajalle"),
+ ("Vuokranantajan velvollisuudet", list_h3, "Vuokranantaja sitoutuu toimittamaan sovittuna ajankohtana Vuokraajalle erikseen sovittava (liite) määrä tanssimattoja."),
+ ("Blaa Blaa", list_h3, "Etc."),
+ ]),
+ ("Tätä sopimusta ja sitä koskevia erimielisyyksiä koskevat määräykset", list_h2, None, tree_seq(), [
+ ("Sopimuksen voimassaolo", list_h3, "Sopimus on osapuolia sitova sen jälkeen, kun osapuolet ovat sen allekirjoittaneet."),
+ ("Muutosten tekeminen", list_h3, "Muutokset sopimukseen on tehtävä kirjallisesti molempien osapuolten kesken."),
+ ("Blaa Blaa", list_h3, "Etc."),
+ ]),
+ ])
+
+ def fmt_tree (bullet, title, title_style, text, seq=None, sublist=[]) :
+ log.debug("bullet(%r) = %r", title, bullet)
+
+ # fixed
+ text_style = list_text
+
+ # first line, with possible bullet
+ if title :
+ yield rlpp.Paragraph(title, title_style, bullet)
+
+ elif text :
+ yield rlpp.Paragraph(text, text_style, bullet)
+
+ if title and text :
+ # indented text after title
+ yield rlpp.Paragraph(text, text_style)
+
+ if sublist :
+ # following lines, indented
+ yield rlpp.Indenter(list_indent)
+
+ # sub-items
+ for item in sublist :
+ # get bullet for item
+ bullet = next(seq, None) if seq else None
+
+ for element in fmt_tree(bullet, *item) :
+ yield element
+
+ # de-dent
+ yield rlpp.Indenter(-list_indent)
+
+ class SignatureBlock (rlpp.Flowable) :
+
+ # vertical space per field
+ FIELD_HEIGHT = 2 * inch / 4
+
+ COL_WIDTH_MAX = 4 * inch
+
+ PADDING_BOTTOM = inch / 2
+
+ def __init__ (self, cols, fields, values) :
+ """
+ cols - Column titles
+ fields - Fields titles, describing the horizontal fields
+ values - Pre-filled values as a {(col, field): value} dict
+
+ desc/value strings can contain formatting codes:
+
+ column - title of the current column
+ today - today's date in %d/%m/%Y format
+ """
+
+ self.cols = cols
+ self.fields = fields
+ self.values = values
+
+ def wrap (self, width, height) :
+ """
+ Calculate how much space we use up, returning (width, height)
+ """
+
+ self.width = width
+
+ # consume all available height, to place us at the bottom
+ self.height = max(len(self.fields) * self.FIELD_HEIGHT, height)
+
+ return self.width, self.height
+
+ def formatString (self, text, col_title) :
+ return text % dict(
+ column = col_title,
+ today = datetime.date.today().strftime("%d/%m/%Y"),
+ )
+
+ def draw (self) :
+ # target canvas
+ canvas = self.canv
+
+ col_width = min(self.width / len(self.cols), self.COL_WIDTH_MAX)
+ col_margin = col_width * 0.1
+ col_height = len(self.fields) * self.FIELD_HEIGHT + self.PADDING_BOTTOM
+
+ for field_idx, (field_title) in enumerate(self.fields) :
+ h = self.FIELD_HEIGHT
+ y = col_height - h * (field_idx + 1)
+
+ for col_idx, (col_title) in enumerate(self.cols) :
+ w = col_width
+ x = w * col_idx
+ value = self.values.get((col_title, field_title))
+ title = field_title
+
+ value = self.formatString(value, col_title) if value else None
+ title = self.formatString(title, col_title) if title else None
+
+ if value :
+ canvas.setFont("Courier-Bold", 14)
+ canvas.drawString(x + col_margin + inch / 12, y - h / 2 + 2, value)
+
+ # field line
+ canvas.line(x + col_margin, y - h / 2, x + w - col_margin, y - h / 2)
+
+ # desc text
+ canvas.setFont("Times-Italic", 10)
+ canvas.drawString(x + col_margin + inch / 8, y - h / 2 - 10, title)
+
elements = [
- rlpp.Paragraph("Hello, World!\n" + title, style)
+ rlpp.Paragraph("Vuokrasopimus", h1),
+ rlpp.Paragraph("Teekkarispeksi ry AV-tekniikka", h3),
+ ] + list(fmt_tree(None, *tree)) + [
+ rlpp.Paragraph("Nouto", h2),
+ rlpp.Paragraph("\t\tAika: _______________\tPaikka: _______________", text),
+ rlpp.Paragraph("Palautus", h2),
+ rlpp.Paragraph("\t\tAika: _______________\tPaikka: _______________", text),
+
+ SignatureBlock(("Vuokranantaja", "Vuokraaja"), ("%(column)s", "Nimen selvennys", "Aika ja paikka"), {
+ ('Vuokranantaja', 'Nimen selvennys'): "Joel Pirttimaa",
+ ('Vuokranantaja', 'Aika ja paikka'): 'Otaniemi, %(today)s',
+ ('Vuokraaja', 'Aika ja paikka'): 'Otaniemi, %(today)s',
+ }),
]
-
+
# render elements to buf as PDF code
doc.build(elements)