diff --git a/extras/win32-portable/create_portable.txt b/extras/win32-portable/create_portable.txt index 5c5fa2c41..4cad67913 100644 --- a/extras/win32-portable/create_portable.txt +++ b/extras/win32-portable/create_portable.txt @@ -4,7 +4,7 @@ How to create a new portable Windows distribution of OpenSlides: 1.) Follow the OpenSlides installation instructions for windows, but add the option "-Z" when executing easy_install, e.g.: - easy_install -Z django django-mptt reportlab pil + easy_install -Z django django-mptt beautifulsoup4 bleach pillow qrcode reportlab tornado 2.) Run in the main directory of the OpenSlides checkout: @@ -14,5 +14,5 @@ How to create a new portable Windows distribution of OpenSlides: in the 'dist' directory -NOTE: Creating the portable Windows distribution of OpenSlides is not possible, -if Python is installed in 64-bit version. +NOTE: Creating the portable Windows distribution of OpenSlides is not possible +if Python is installed in 64-bit(!) version. diff --git a/extras/win32-portable/prepare_portable.py b/extras/win32-portable/prepare_portable.py index b1a2b5815..9bc7db2b7 100644 --- a/extras/win32-portable/prepare_portable.py +++ b/extras/win32-portable/prepare_portable.py @@ -90,6 +90,15 @@ SITE_PACKAGES = { }, "qrcode": { "copy": ["qrcode"], + }, + "beautifulsoup4": { + "copy": ["bs4"], + }, + "bleach": { + "copy": ["bleach"], + }, + "html5lib": { + "copy": ["html5lib"], } } diff --git a/openslides/motion/pdf.py b/openslides/motion/pdf.py index 7f48ec7dd..038933232 100644 --- a/openslides/motion/pdf.py +++ b/openslides/motion/pdf.py @@ -10,6 +10,9 @@ :license: GNU GPL, see LICENSE for more details. """ +import random +from bs4 import BeautifulSoup + from reportlab.lib import colors from reportlab.lib.units import cm from reportlab.platypus import ( @@ -147,14 +150,89 @@ def motion_to_pdf(pdf, motion): pdf.append(table) pdf.append(Spacer(0, 1 * cm)) + # motion title pdf.append(Paragraph(motion.title, stylesheet['Heading3'])) - pdf.append(Paragraph(motion.text.replace('\r\n', '
'), stylesheet['Paragraph'])) + + # motion text + convert_html_to_reportlab(pdf, motion.text) + pdf.append(Spacer(0, 1 * cm)) + + # motion reason if motion.reason: pdf.append(Paragraph(_("Reason:"), stylesheet['Heading3'])) - pdf.append(Paragraph(motion.reason.replace('\r\n', '
'), stylesheet['Paragraph'])) + convert_html_to_reportlab(pdf, motion.reason) return pdf +def convert_html_to_reportlab(pdf, text): + # parsing and replacing not supported html tags for reportlab... + soup = BeautifulSoup(text) + # read all list elements... + for element in soup.find_all('li'): + try: + # ... and replace ul list elements with ... + if element.parent.name == "ul": + if element.ul: + # for nested ul lists use simple spaces (pragmatic solution) + element.li.insert(0,'    ') + element.insert_before(element.find_all('li')) + element.clear() + else: + element.name = "para" + bullet_tag = soup.new_tag("bullet") + bullet_tag.string = "•" + element.insert(0, bullet_tag) + # ... and replace ol list elements with .... + if element.parent.name == "ol": + # set list id if element is the first of numbered list + if not element.find_previous_sibling(): + id = random.randrange(0, 101) + if element.ol: + # nested ol list + element.li.insert(0,'    ') + element.insert_before(element.find_all('li')) + element.clear() + else: + element.name = "para" + element.insert(0, soup.new_tag("bullet")) + element.bullet.insert(0, soup.new_tag("seq")) + element.bullet.seq['id'] = id + element.bullet.insert(1, ".") + except AttributeError: + pass + # remove tags which are not supported by reportlab (replace tags with their children tags) + for tag in soup.find_all('ul'): + tag.unwrap() + for tag in soup.find_all('ol'): + tag.unwrap() + for tag in soup.find_all('li'): + tag.unwrap() + # print paragraphs with numbers + text = soup.body.contents + paragraph_number = 1 + for paragraph in text: + paragraph = str(paragraph) + # ignore empty paragraphs (created by newlines/tabs of ckeditor) + if paragraph == '\n' or paragraph == '\n\n' or paragraph == '\n\t': + continue + if "
" in paragraph:
+            pdf.append(Paragraph(paragraph.replace('\n', '
'), stylesheet['InnerMonotypeParagraph'], str(paragraph_number))) + paragraph_number += 1 + elif "" in paragraph: + pdf.append(Paragraph(paragraph, stylesheet['InnerListParagraph'])) + elif "" in paragraph: + pdf.append(Paragraph(paragraph, stylesheet['InnerH1Paragraph'])) + elif "

" in paragraph: + pdf.append(Paragraph(paragraph, stylesheet['InnerH2Paragraph'])) + elif "

" in paragraph: + pdf.append(Paragraph(paragraph, stylesheet['InnerH3Paragraph'])) + else: + pdf.append(Paragraph(str(paragraph), stylesheet['InnerParagraph'], str(paragraph_number))) + paragraph_number += 1 + + def all_motion_cover(pdf, motions): """Create a coverpage for all motions.""" pdf.append(Paragraph(config["motion_pdf_title"], stylesheet['Heading1'])) diff --git a/openslides/utils/pdf.py b/openslides/utils/pdf.py index 10cad58c0..7dd9a8425 100755 --- a/openslides/utils/pdf.py +++ b/openslides/utils/pdf.py @@ -13,6 +13,7 @@ from datetime import datetime from os.path import join as path_join +from reportlab.lib import colors from reportlab.lib.styles import StyleSheet1, ParagraphStyle from reportlab.lib.units import cm from reportlab.pdfbase import pdfmetrics @@ -44,7 +45,7 @@ PAGE_WIDTH = defaultPageSize[0] stylesheet = StyleSheet1() stylesheet.add(ParagraphStyle( name='Normal', - fontName='Ubuntu', + #fontName='Ubuntu', fontSize=10, leading=12, )) @@ -54,6 +55,51 @@ stylesheet.add(ParagraphStyle( leading=14, spaceAfter=15 )) +stylesheet.add(ParagraphStyle( + name='InnerParagraph', + parent=stylesheet['Normal'], + leading=14, + spaceBefore=5, + spaceAfter=5, + bulletIndent=-15, + bulletFontSize=8, + bulletColor=colors.grey +)) +stylesheet.add(ParagraphStyle( + name='InnerListParagraph', + parent=stylesheet['InnerParagraph'], + bulletIndent=10, + bulletFontSize=10, + bulletColor=colors.black, + leftIndent = 30 +)) +stylesheet.add(ParagraphStyle( + name='InnerMonotypeParagraph', + parent=stylesheet['InnerParagraph'], + fontName='Courier', +)) +stylesheet.add(ParagraphStyle( + name='InnerH1Paragraph', + parent=stylesheet['InnerParagraph'], + fontName='Ubuntu-Bold', + fontSize=16, + spaceBefore=20, + spaceAfter=10, +)) +stylesheet.add(ParagraphStyle( + name='InnerH2Paragraph', + parent=stylesheet['InnerH1Paragraph'], + fontSize=12, + spaceBefore=20, + spaceAfter=10, +)) +stylesheet.add(ParagraphStyle( + name='InnerH3Paragraph', + parent=stylesheet['InnerH2Paragraph'], + fontSize=10, + spaceBefore=15, + spaceAfter=5, +)) stylesheet.add(ParagraphStyle( name='Small', parent=stylesheet['Normal'], diff --git a/requirements.txt b/requirements.txt index 794e1e3e3..c7ded514d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,8 @@ +# Requirements for OpenSlides Core Django==1.5.1 django-mptt==0.5.5 +beautifulsoup4==4.1.3 +bleach==1.2.1 pillow==2.0.0 qrcode==2.7 reportlab==2.7 @@ -10,4 +13,3 @@ Fabric==1.6.0 coverage==3.6 django-discover-runner==0.3 pep8==1.4.5 -bleach