Merge commit '7addd69050a69b9d02aacba116939829497ca338' into MergeStablePart2
Conflicts: extras/win32-portable/create_portable.txt extras/win32-portable/prepare_portable.py openslides/assignment/views.py openslides/core/static/img/circle.png openslides/motion/pdf.py openslides/utils/pdf.py
This commit is contained in:
commit
3d7ecab8e4
@ -42,6 +42,7 @@ Participant:
|
|||||||
Files:
|
Files:
|
||||||
- Fixed error when a file was removed from filesystem.
|
- Fixed error when a file was removed from filesystem.
|
||||||
Other:
|
Other:
|
||||||
|
- Used unicode font for circle in ballot pdf. Removed pillow dependency package.
|
||||||
- Fixed http status code when requesting a non-existing static page using
|
- Fixed http status code when requesting a non-existing static page using
|
||||||
Tordado web server.
|
Tordado web server.
|
||||||
- Fixed error in main script when using other database engine.
|
- Fixed error in main script when using other database engine.
|
||||||
|
@ -84,8 +84,7 @@ portable version you should observe the following install steps.*
|
|||||||
<http://www.python.org/ftp/python/2.7.5/python-2.7.5.msi>`_. Note
|
<http://www.python.org/ftp/python/2.7.5/python-2.7.5.msi>`_. Note
|
||||||
that the 32-bit MSI installer is required even on a 64-bit Windows
|
that the 32-bit MSI installer is required even on a 64-bit Windows
|
||||||
system. If you use the 64-bit MSI installer, step 3 of this
|
system. If you use the 64-bit MSI installer, step 3 of this
|
||||||
instruction will fail unless you installed the packages reportlab and
|
instruction will fail unless you installed the packages reportlab manually.
|
||||||
pillow manually.
|
|
||||||
|
|
||||||
b. Add python directories to PATH (via Control Panel > System >
|
b. Add python directories to PATH (via Control Panel > System >
|
||||||
Advanced): ``";C:\\Python27;C:\\Python27\\Scripts"``. Note that the path
|
Advanced): ``";C:\\Python27;C:\\Python27\\Scripts"``. Note that the path
|
||||||
@ -260,9 +259,6 @@ OpenSlides uses the following projects or parts of them:
|
|||||||
|
|
||||||
* `pdf.js <http://mozilla.github.io/pdf.js/>`_, License: Apache License v2.0
|
* `pdf.js <http://mozilla.github.io/pdf.js/>`_, License: Apache License v2.0
|
||||||
|
|
||||||
* `Pillow <https://github.com/python-imaging/Pillow/>`_, License: Standard
|
|
||||||
PIL License
|
|
||||||
|
|
||||||
* `ReportLab <http://www.reportlab.com/software/opensource/rl-toolkit/>`_,
|
* `ReportLab <http://www.reportlab.com/software/opensource/rl-toolkit/>`_,
|
||||||
License: BSD
|
License: BSD
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ How to create a new portable Windows distribution of OpenSlides:
|
|||||||
|
|
||||||
2. Install all required python packages (see requirements_production.txt):
|
2. Install all required python packages (see requirements_production.txt):
|
||||||
|
|
||||||
easy_install -Z django django-mptt beautifulsoup4 bleach jsonfield natsort pillow reportlab setuptools sockjs_tornado tornado django-haystack whoosh
|
easy_install -Z django django-mptt beautifulsoup4 bleach jsonfield natsort reportlab setuptools sockjs_tornado tornado django-haystack whoosh
|
||||||
|
|
||||||
|
|
||||||
3. Install pywin32 from binary installer:
|
3. Install pywin32 from binary installer:
|
||||||
@ -34,3 +34,4 @@ How to create a new portable Windows distribution of OpenSlides:
|
|||||||
|
|
||||||
NOTE: Creating the portable Windows distribution of OpenSlides is not possible
|
NOTE: Creating the portable Windows distribution of OpenSlides is not possible
|
||||||
if Python is installed in 64-bit(!) version.
|
if Python is installed in 64-bit(!) version.
|
||||||
|
|
||||||
|
@ -78,9 +78,6 @@ SITE_PACKAGES = {
|
|||||||
"jsonfield": {
|
"jsonfield": {
|
||||||
"copy": ["jsonfield"],
|
"copy": ["jsonfield"],
|
||||||
},
|
},
|
||||||
"pillow": {
|
|
||||||
"copy": ["PIL"],
|
|
||||||
},
|
|
||||||
"reportlab": {
|
"reportlab": {
|
||||||
"copy": [
|
"copy": [
|
||||||
"reportlab",
|
"reportlab",
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
@ -506,8 +503,7 @@ class AssignmentPollPDF(PDFView):
|
|||||||
pdf_document.build(story)
|
pdf_document.build(story)
|
||||||
|
|
||||||
def append_to_pdf(self, story):
|
def append_to_pdf(self, story):
|
||||||
imgpath = os.path.join(settings.SITE_ROOT, 'core', 'static', 'img', 'circle.png')
|
circle = "*" # = Unicode Character 'HEAVY LARGE CIRCLE' (U+2B55)
|
||||||
circle = "<img src='%s' width='15' height='15'/> " % imgpath
|
|
||||||
cell = []
|
cell = []
|
||||||
cell.append(Spacer(0, 0.8 * cm))
|
cell.append(Spacer(0, 0.8 * cm))
|
||||||
cell.append(Paragraph(
|
cell.append(Paragraph(
|
||||||
@ -547,25 +543,43 @@ class AssignmentPollPDF(PDFView):
|
|||||||
number = int(ballot_papers_number)
|
number = int(ballot_papers_number)
|
||||||
number = max(1, number)
|
number = max(1, number)
|
||||||
|
|
||||||
# Choose kind of ballot paper
|
counter = 0
|
||||||
if self.poll.yesnoabstain:
|
cellcolumnA = []
|
||||||
|
# Choose kind of ballot paper (YesNoAbstain or Yes)
|
||||||
|
if self.poll.yesnoabstain: # YesNoAbstain ballot: max 27 candidates
|
||||||
for option in options:
|
for option in options:
|
||||||
|
counter += 1
|
||||||
candidate = option.candidate
|
candidate = option.candidate
|
||||||
cell.append(Paragraph(
|
cell.append(Paragraph(
|
||||||
candidate.clean_name, stylesheet['Ballot_option_name']))
|
candidate.clean_name, stylesheet['Ballot_option_name_YNA']))
|
||||||
if candidate.name_suffix:
|
if candidate.name_suffix:
|
||||||
cell.append(Paragraph(
|
cell.append(Paragraph(
|
||||||
"(%s)" % candidate.name_suffix,
|
"(%s)" % candidate.name_suffix,
|
||||||
stylesheet['Ballot_option_group']))
|
stylesheet['Ballot_option_suffix_YNA']))
|
||||||
else:
|
else:
|
||||||
cell.append(Paragraph(
|
cell.append(Paragraph(
|
||||||
" ", stylesheet['Ballot_option_group']))
|
" ", stylesheet['Ballot_option_suffix_YNA']))
|
||||||
cell.append(Paragraph(
|
cell.append(Paragraph("<font name='circlefont' size='15'>%(circle)s</font> \
|
||||||
circle + _("Yes") + " " * 3 + circle
|
<font name='Ubuntu'>%(yes)s </font> \
|
||||||
+ _("No") + " " * 3 + circle + _("Abstention"),
|
<font name='circlefont' size='15'>%(circle)s</font> \
|
||||||
stylesheet['Ballot_option_YNA']))
|
<font name='Ubuntu'>%(no)s </font> \
|
||||||
|
<font name='circlefont' size='15'>%(circle)s</font> \
|
||||||
|
<font name='Ubuntu'>%(abstain)s</font>" %
|
||||||
|
{'circle': circle,
|
||||||
|
'yes': _("Yes"),
|
||||||
|
'no': _("No"),
|
||||||
|
'abstain': _("Abstention")},
|
||||||
|
stylesheet['Ballot_option_circle_YNA']))
|
||||||
|
if counter == 13:
|
||||||
|
cellcolumnA = cell
|
||||||
|
cell = []
|
||||||
|
cell.append(Spacer(0, 1.3 * cm))
|
||||||
|
|
||||||
# print ballot papers
|
# print ballot papers
|
||||||
for user in xrange(number / 2):
|
for user in xrange(number / 2):
|
||||||
|
if len(options) > 13:
|
||||||
|
data.append([cellcolumnA, cell])
|
||||||
|
else:
|
||||||
data.append([cell, cell])
|
data.append([cell, cell])
|
||||||
rest = number % 2
|
rest = number % 2
|
||||||
if rest:
|
if rest:
|
||||||
@ -576,21 +590,30 @@ class AssignmentPollPDF(PDFView):
|
|||||||
t = Table(data, 10.5 * cm, 14.84 * cm)
|
t = Table(data, 10.5 * cm, 14.84 * cm)
|
||||||
else:
|
else:
|
||||||
t = Table(data, 10.5 * cm, 29.7 * cm)
|
t = Table(data, 10.5 * cm, 29.7 * cm)
|
||||||
else:
|
else: # Yes ballot: max 46 candidates
|
||||||
for option in options:
|
for option in options:
|
||||||
|
counter += 1
|
||||||
candidate = option.candidate
|
candidate = option.candidate
|
||||||
cell.append(Paragraph(
|
cell.append(Paragraph("<font name='circlefont' size='15'>%s</font> \
|
||||||
circle + candidate.clean_name,
|
<font name='Ubuntu'>%s</font>" %
|
||||||
stylesheet['Ballot_option_name']))
|
(circle, candidate.clean_name), stylesheet['Ballot_option_name']))
|
||||||
if candidate.name_suffix:
|
if candidate.name_suffix:
|
||||||
cell.append(Paragraph(
|
cell.append(Paragraph(
|
||||||
"(%s)" % candidate.name_suffix,
|
"(%s)" % candidate.name_suffix,
|
||||||
stylesheet['Ballot_option_group_right']))
|
stylesheet['Ballot_option_suffix']))
|
||||||
else:
|
else:
|
||||||
cell.append(Paragraph(
|
cell.append(Paragraph(
|
||||||
" ", stylesheet['Ballot_option_group_right']))
|
" ", stylesheet['Ballot_option_suffix']))
|
||||||
|
if counter == 22:
|
||||||
|
cellcolumnA = cell
|
||||||
|
cell = []
|
||||||
|
cell.append(Spacer(0, 0.75 * cm))
|
||||||
|
|
||||||
# print ballot papers
|
# print ballot papers
|
||||||
for user in xrange(number / 2):
|
for user in xrange(number / 2):
|
||||||
|
if len(options) > 22:
|
||||||
|
data.append([cellcolumnA, cell])
|
||||||
|
else:
|
||||||
data.append([cell, cell])
|
data.append([cell, cell])
|
||||||
rest = number % 2
|
rest = number % 2
|
||||||
if rest:
|
if rest:
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 18 KiB |
@ -1,11 +1,9 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
import os
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from django.conf import settings
|
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from natsort import natsorted
|
from natsort import natsorted
|
||||||
from reportlab.lib import colors
|
from reportlab.lib import colors
|
||||||
@ -261,17 +259,19 @@ def all_motion_cover(pdf, motions):
|
|||||||
|
|
||||||
|
|
||||||
def motion_poll_to_pdf(pdf, poll):
|
def motion_poll_to_pdf(pdf, poll):
|
||||||
imgpath = os.path.join(settings.SITE_ROOT, 'core', 'static', 'img', 'circle.png')
|
circle = "*" # = Unicode Character 'HEAVY LARGE CIRCLE' (U+2B55)
|
||||||
circle = "<img src='%s' width='15' height='15'/> " % imgpath
|
|
||||||
cell = []
|
cell = []
|
||||||
cell.append(Spacer(0, 0.8 * cm))
|
cell.append(Spacer(0, 0.8 * cm))
|
||||||
cell.append(Paragraph(_("Motion No. %s") % poll.motion.identifier, stylesheet['Ballot_title']))
|
cell.append(Paragraph(_("Motion No. %s") % poll.motion.identifier, stylesheet['Ballot_title']))
|
||||||
cell.append(Paragraph(poll.motion.title, stylesheet['Ballot_subtitle']))
|
cell.append(Paragraph(poll.motion.title, stylesheet['Ballot_subtitle']))
|
||||||
cell.append(Paragraph(_("%d. Vote") % poll.poll_number, stylesheet['Ballot_description']))
|
cell.append(Paragraph(_("%d. Vote") % poll.poll_number, stylesheet['Ballot_description']))
|
||||||
cell.append(Spacer(0, 0.5 * cm))
|
cell.append(Spacer(0, 0.5 * cm))
|
||||||
cell.append(Paragraph(circle + unicode(_("Yes")), stylesheet['Ballot_option']))
|
cell.append(Paragraph("<font name='circlefont' size='15'>%s</font> <font name='Ubuntu'>%s</font>"
|
||||||
cell.append(Paragraph(circle + unicode(_("No")), stylesheet['Ballot_option']))
|
% (circle, unicode(_("Yes"))), stylesheet['Ballot_option']))
|
||||||
cell.append(Paragraph(circle + unicode(_("Abstention")), stylesheet['Ballot_option']))
|
cell.append(Paragraph("<font name='circlefont' size='15'>%s</font> <font name='Ubuntu'>%s</font>"
|
||||||
|
% (circle, unicode(_("No"))), stylesheet['Ballot_option']))
|
||||||
|
cell.append(Paragraph("<font name='circlefont' size='15'>%s</font> <font name='Ubuntu'>%s</font>"
|
||||||
|
% (circle, unicode(_("Abstention"))), stylesheet['Ballot_option']))
|
||||||
data = []
|
data = []
|
||||||
# get ballot papers config values
|
# get ballot papers config values
|
||||||
ballot_papers_selection = config["motion_pdf_ballot_papers_selection"]
|
ballot_papers_selection = config["motion_pdf_ballot_papers_selection"]
|
||||||
|
16
openslides/static/fonts/README.txt
Normal file
16
openslides/static/fonts/README.txt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
This directory contains truetype fonts which are used for PDF generation in OpenSlides.
|
||||||
|
They are registered in the file 'openslides/utils/pdf.py'.
|
||||||
|
|
||||||
|
The Ubuntu font is available in three styles: Regular, Bold and Italic.
|
||||||
|
|
||||||
|
If you want to use your own font just replace the Ubuntu font with your truetype font files.
|
||||||
|
Or you have to change the filename in the registerFont function in pdf.py. Please note
|
||||||
|
that the font name 'Ubuntu' is already used in some stylesheets in the same file.
|
||||||
|
|
||||||
|
The font file circle.ttf contains only the unicode character 'HEAVY LARGE CIRCLE' (U+2B55)
|
||||||
|
which is extracted from the free unicode font "Quivira 4.0" [1] with the freeware
|
||||||
|
OpenType font editor "Type light" [2]. The circle glyph is mapped to the '*' character
|
||||||
|
for using in OpenSlides PDF ballot papers of motions and elections.
|
||||||
|
|
||||||
|
[1] http://www.quivira-font.com/
|
||||||
|
[2] http://www.cr8software.net/typelight.html
|
BIN
openslides/static/fonts/circle.ttf
Normal file
BIN
openslides/static/fonts/circle.ttf
Normal file
Binary file not shown.
@ -21,7 +21,8 @@ pdfmetrics.registerFont(TTFont(
|
|||||||
pdfmetrics.registerFont(TTFont(
|
pdfmetrics.registerFont(TTFont(
|
||||||
'Ubuntu-Bold', path_join(settings.SITE_ROOT, 'core/static/fonts/Ubuntu-B.ttf')))
|
'Ubuntu-Bold', path_join(settings.SITE_ROOT, 'core/static/fonts/Ubuntu-B.ttf')))
|
||||||
pdfmetrics.registerFont(TTFont(
|
pdfmetrics.registerFont(TTFont(
|
||||||
'Ubuntu-Italic', path_join(settings.SITE_ROOT, 'core/static/fonts/Ubuntu-RI.ttf')))
|
pdfmetrics.registerFont(TTFont(
|
||||||
|
'circlefont', path_join(settings.SITE_ROOT, 'core/static/fonts/circle.ttf')))
|
||||||
|
|
||||||
|
|
||||||
# set style information
|
# set style information
|
||||||
@ -185,30 +186,29 @@ stylesheet.add(ParagraphStyle(name='Ballot_option',
|
|||||||
leading=24,
|
leading=24,
|
||||||
leftIndent=30),
|
leftIndent=30),
|
||||||
)
|
)
|
||||||
|
stylesheet.add(ParagraphStyle(name='Ballot_option_name_YNA',
|
||||||
|
parent=stylesheet['Ballot_option'],
|
||||||
|
leading=14),
|
||||||
|
)
|
||||||
stylesheet.add(ParagraphStyle(name='Ballot_option_name',
|
stylesheet.add(ParagraphStyle(name='Ballot_option_name',
|
||||||
parent=stylesheet['Normal'],
|
parent=stylesheet['Ballot_option_name_YNA'],
|
||||||
fontSize=12,
|
leading=17),
|
||||||
leading=15,
|
|
||||||
leftIndent=30),
|
|
||||||
)
|
)
|
||||||
stylesheet.add(ParagraphStyle(name='Ballot_option_group',
|
|
||||||
parent=stylesheet['Normal'],
|
stylesheet.add(ParagraphStyle(name='Ballot_option_suffix_YNA',
|
||||||
|
parent=stylesheet['Ballot_option_name_YNA'],
|
||||||
fontSize=8,
|
fontSize=8,
|
||||||
leading=15,
|
leading=11),
|
||||||
leftIndent=30),
|
|
||||||
)
|
)
|
||||||
stylesheet.add(ParagraphStyle(name='Ballot_option_YNA',
|
stylesheet.add(ParagraphStyle(name='Ballot_option_suffix',
|
||||||
parent=stylesheet['Normal'],
|
parent=stylesheet['Ballot_option_suffix_YNA'],
|
||||||
fontSize=12,
|
|
||||||
leading=15,
|
|
||||||
leftIndent=49,
|
|
||||||
spaceAfter=18),
|
|
||||||
)
|
|
||||||
stylesheet.add(ParagraphStyle(name='Ballot_option_group_right',
|
|
||||||
parent=stylesheet['Normal'],
|
|
||||||
fontSize=8,
|
|
||||||
leading=16,
|
leading=16,
|
||||||
leftIndent=49),
|
leftIndent=48),
|
||||||
|
)
|
||||||
|
stylesheet.add(ParagraphStyle(name='Ballot_option_circle_YNA',
|
||||||
|
parent=stylesheet['Ballot_option_name_YNA'],
|
||||||
|
leftIndent=48,
|
||||||
|
spaceAfter=18),
|
||||||
)
|
)
|
||||||
# Password paper stylesheets
|
# Password paper stylesheets
|
||||||
stylesheet.add(ParagraphStyle(name='formfield',
|
stylesheet.add(ParagraphStyle(name='formfield',
|
||||||
|
@ -6,7 +6,6 @@ django-haystack>=2.1,<2.2
|
|||||||
django-mptt>=0.6,<0.7
|
django-mptt>=0.6,<0.7
|
||||||
jsonfield>=0.9,<0.10
|
jsonfield>=0.9,<0.10
|
||||||
natsort>=3.0,<3.1
|
natsort>=3.0,<3.1
|
||||||
pillow>=2.2,<2.3
|
|
||||||
reportlab>=2.7,<2.8
|
reportlab>=2.7,<2.8
|
||||||
setuptools>=2.1,<2.2
|
setuptools>=2.1,<2.2
|
||||||
sockjs-tornado>=1.0,<1.1
|
sockjs-tornado>=1.0,<1.1
|
||||||
|
Loading…
Reference in New Issue
Block a user