diff --git a/extras/win32-portable/openslides.exe b/extras/win32-portable/openslides.exe
index fed0eb63a..96fb7ae1f 100644
Binary files a/extras/win32-portable/openslides.exe and b/extras/win32-portable/openslides.exe differ
diff --git a/openslides/assignment/models.py b/openslides/assignment/models.py
index 3f1485ff9..06360cdf3 100644
--- a/openslides/assignment/models.py
+++ b/openslides/assignment/models.py
@@ -12,6 +12,7 @@ from openslides.config.api import config
from openslides.poll.models import (BaseOption, BasePoll, BaseVote,
CollectDefaultVotesMixin,
PublishPollMixin)
+from openslides.projector.api import get_active_object, update_projector
from openslides.projector.models import RelatedModelMixin, SlideMixin
from openslides.utils.exceptions import OpenSlidesError
from openslides.utils.models import AbsoluteUrlMixin
@@ -190,6 +191,11 @@ class Assignment(SlideMixin, AbsoluteUrlMixin, models.Model):
candidate = self.assignment_candidates.get(person=person)
candidate.elected = value
candidate.save()
+ # update projector if assignment or assignmentpoll slide is active
+ active_object = get_active_object()
+ if (type(active_object) is type(self) and active_object.pk == self.pk) or \
+ (type(active_object) is AssignmentPoll and active_object.assignment_id == self.pk):
+ update_projector()
def is_elected(self, person):
return person in self.elected
@@ -271,8 +277,12 @@ class AssignmentOption(BaseOption):
return unicode(self.candidate)
-class AssignmentPoll(RelatedModelMixin, CollectDefaultVotesMixin,
+class AssignmentPoll(SlideMixin, RelatedModelMixin, CollectDefaultVotesMixin,
PublishPollMixin, AbsoluteUrlMixin, BasePoll):
+
+ slide_callback_name = 'assignmentpoll'
+ """Name of the callback for the slide-system."""
+
option_class = AssignmentOption
assignment = models.ForeignKey(Assignment, related_name='poll_set')
yesnoabstain = models.NullBooleanField()
@@ -284,10 +294,15 @@ class AssignmentPoll(RelatedModelMixin, CollectDefaultVotesMixin,
return _("Ballot %d") % self.get_ballot()
def get_absolute_url(self, link='update'):
+ """
+ Return an URL for the poll.
+
+ The keyargument 'link' can be 'update' or 'delete'.
+ """
if link == 'update':
- url = reverse('assignment_poll_view', args=[str(self.pk)])
+ url = reverse('assignmentpoll_update', args=[str(self.pk)])
elif link == 'delete':
- url = reverse('assignment_poll_delete', args=[str(self.pk)])
+ url = reverse('assignmentpoll_delete', args=[str(self.pk)])
else:
url = super(AssignmentPoll, self).get_absolute_url(link)
return url
@@ -325,3 +340,6 @@ class AssignmentPoll(RelatedModelMixin, CollectDefaultVotesMixin,
def append_pollform_fields(self, fields):
fields.append('description')
super(AssignmentPoll, self).append_pollform_fields(fields)
+
+ def get_slide_context(self, **context):
+ return super(AssignmentPoll, self).get_slide_context(poll=self)
diff --git a/openslides/assignment/signals.py b/openslides/assignment/signals.py
index 642eab5f3..88b4c745f 100644
--- a/openslides/assignment/signals.py
+++ b/openslides/assignment/signals.py
@@ -59,8 +59,8 @@ def setup_assignment_config(sender, **kwargs):
default_value=False,
form_field=forms.BooleanField(
required=False,
- label=ugettext_lazy('Only publish voting results for selected '
- 'winners (Projector view only)')))
+ label=ugettext_lazy('Publish election result for elected candidates only '
+ '(projector view)')))
group_ballot = ConfigGroup(
title=ugettext_lazy('Ballot and ballot papers'),
variables=(assignment_poll_vote_values,
diff --git a/openslides/assignment/slides.py b/openslides/assignment/slides.py
index 9435b25f1..edfa347ef 100644
--- a/openslides/assignment/slides.py
+++ b/openslides/assignment/slides.py
@@ -2,6 +2,7 @@
from openslides.projector.api import register_slide_model
-from .models import Assignment
+from .models import Assignment, AssignmentPoll
register_slide_model(Assignment, 'assignment/slide.html')
+register_slide_model(AssignmentPoll, 'assignment/assignmentpoll_slide.html')
diff --git a/openslides/assignment/templates/assignment/assignment_detail.html b/openslides/assignment/templates/assignment/assignment_detail.html
index f833af89b..70d14af5e 100644
--- a/openslides/assignment/templates/assignment/assignment_detail.html
+++ b/openslides/assignment/templates/assignment/assignment_detail.html
@@ -18,6 +18,8 @@
{% block content %}
{{ assignment }}
+
+ {% trans "Election" %}
{% trans "Back to overview" %}
PDF
@@ -141,9 +143,9 @@
{% endif %}
-
+
{% if assignment.status != "sea" or polls.exists %}
- {% trans "Election results" %}
+ {% trans "Election result" %}
{% if polls.exists %}
@@ -154,8 +156,8 @@
{{ poll.get_ballot|ordinal|safe }} {% trans 'ballot' %}
{% if perms.assignment.can_manage_assignment %}
+ href="{% url 'assignmentpoll_publish_status' poll.id %}"
+ rel="tooltip" data-original-title="{% trans 'Publish result' %}">
{% if poll.published %}
{% else %}
@@ -164,11 +166,15 @@
-
+
+
-
-
{% endif %}
@@ -176,7 +182,7 @@
{% endfor %}
{% if assignment.candidates and perms.assignment.can_manage_assignment and assignment.status == "vot" %}
-
+
{% trans 'New ballot' %}
|
@@ -275,7 +281,7 @@
{% trans "No ballots available." %}
{% if assignment.candidates and perms.assignment.can_manage_assignment and assignment.status == "vot" %}
-
+
{% trans 'New ballot' %}
diff --git a/openslides/assignment/templates/assignment/poll_view.html b/openslides/assignment/templates/assignment/assignmentpoll_form.html
similarity index 68%
rename from openslides/assignment/templates/assignment/poll_view.html
rename to openslides/assignment/templates/assignment/assignmentpoll_form.html
index 961397612..8ccd879e9 100644
--- a/openslides/assignment/templates/assignment/poll_view.html
+++ b/openslides/assignment/templates/assignment/assignmentpoll_form.html
@@ -13,15 +13,22 @@
{{ ballotnumber|ordinal|safe }} {% trans "ballot" %}
- {% trans "Back to election" %}
-
- {% if perms.core.can_manage_projector %}
-
-
-
- {% endif %}
+ {% trans "Back to election" %}
+
+ {% if perms.core.can_manage_projector %}
+
+
+
+
+ {% trans "Vote result" %}
+ {% endif %}
+ {% if perms.motion.can_manage_motion %}
+
+ {% endif %}
@@ -50,7 +57,7 @@
{% endfor %}
{% endfor %}
-
+
{% trans "Valid votes" %} |
{% for value in poll.get_vote_values %}
{% if forloop.first %}
@@ -85,7 +92,7 @@
{% trans "Short description (for ballot paper)" %}:
{{ pollform.description }}
-
+
{% trans 'Ballot paper as PDF' %}
diff --git a/openslides/assignment/templates/assignment/assignmentpoll_slide.html b/openslides/assignment/templates/assignment/assignmentpoll_slide.html
new file mode 100644
index 000000000..ac702cdd9
--- /dev/null
+++ b/openslides/assignment/templates/assignment/assignmentpoll_slide.html
@@ -0,0 +1,59 @@
+{% load i18n %}
+{% load humanize %}
+{% load staticfiles %}
+{% load tags %}
+
+
+ {{ poll.assignment }}
+
+
+ {% trans "Election" %}
+ {% if poll.get_ballot > 1 %}| {{ poll.get_ballot|ordinal|safe }} {% trans "ballot" %}{% endif %}
+
+
+
+
+{% if poll.has_votes and poll.published %}
+
+ {% for option in poll.get_options %}
+
+ {{ option }} |
+
+ {% if not "assignment_publish_winner_results_only"|get_config or option.candidate in poll.assignment.elected %}
+ {% if poll.yesnoabstain %}
+ {% trans 'Yes' %}:
+ {{ option.Yes }}
+ {% trans 'No' %}:
+ {{ option.No }}
+ {% trans 'Abstention' %}:
+ {{ option.Abstain }}
+ {% else %}
+ {{ option.Votes }}
+ {% endif %}
+ {% endif %}
+ |
+
+ {% endfor %}
+ {% if poll.votesvalid != None %}
+
+ {% trans 'Valid votes' %}: |
+ {{ poll.print_votesvalid }} |
+
+ {% endif %}
+ {% if poll.votesinvalid != None %}
+
+ {% trans 'Invalid votes' %}: |
+ {{ poll.print_votesinvalid }} |
+
+ {% endif %}
+ {% if poll.votescast != None %}
+
+ {% trans 'Votes cast' %}: |
+ {{ poll.print_votescast }} |
+
+ {% endif %}
+
+{% else %}
+ {% trans "No result available." %}
+{% endif %}
+
diff --git a/openslides/assignment/templates/assignment/slide.html b/openslides/assignment/templates/assignment/slide.html
index aec360c7e..96c8dca1b 100644
--- a/openslides/assignment/templates/assignment/slide.html
+++ b/openslides/assignment/templates/assignment/slide.html
@@ -1,6 +1,7 @@
{% load i18n %}
{% load staticfiles %}
{% load tags %}
+{% load humanize %}
{% endfor %}
-
+
{% trans "Valid votes" %} |
{{ pollform.votesvalid.errors }}{{ pollform.votesvalid }} |
-
+
{% trans "Invalid votes" %} |
{{ pollform.votesinvalid.errors }}{{ pollform.votesinvalid }} |
-
+
{% trans "Votes cast" %} |
{{ pollform.votescast.errors }}{{ pollform.votescast }} |
@@ -62,7 +68,7 @@
-
+
{% trans 'Ballot paper as PDF' %}
diff --git a/openslides/motion/templates/motion/motionpoll_slide.html b/openslides/motion/templates/motion/motionpoll_slide.html
new file mode 100644
index 000000000..cc1fa0977
--- /dev/null
+++ b/openslides/motion/templates/motion/motionpoll_slide.html
@@ -0,0 +1,54 @@
+{% load i18n %}
+{% load humanize %}
+{% load staticfiles %}
+
+
+ {{ poll.motion.active_version.title }}
+
+
+ {% trans "Motion" %} {{ poll.motion.identifier|default:'' }}
+ {% if poll.motion.get_active_version.version_number > 1 %} | {% trans 'Version' %} {{ poll.motion.active_version.version_number }}{% endif %}
+ {% if poll.poll_number > 1 %}| {{ poll.poll_number|ordinal|safe }} {% trans "vote" %}{% endif %}
+
+
+
+
+ {% if poll.has_votes %}
+ {% with poll.get_options.0 as option %}
+
+
+ {% trans 'Yes' %}: |
+ {{ option.Yes }} |
+
+
+ {% trans 'No' %}: |
+ {{ option.No }} |
+
+
+ {% trans 'Abstention' %}: |
+ {{ option.No }} |
+
+ {% if poll.votesvalid != None %}
+
+ {% trans 'Valid votes' %}: |
+ {{ poll.print_votesvalid }} |
+
+ {% endif %}
+ {% if poll.votesinvalid != None %}
+
+ {% trans 'Invalid votes' %}: |
+ {{ poll.print_votesinvalid }} |
+
+ {% endif %}
+ {% if poll.votescast != None %}
+
+ {% trans 'Votes cast' %}: |
+ {{ poll.print_votescast }} |
+
+ {% endif %}
+
+ {% endwith %}
+ {% else %}
+ {% trans "No result available." %}
+ {% endif %}
+
diff --git a/openslides/motion/templates/motion/slide.html b/openslides/motion/templates/motion/slide.html
index e4f3c4ed2..bd8804385 100644
--- a/openslides/motion/templates/motion/slide.html
+++ b/openslides/motion/templates/motion/slide.html
@@ -8,7 +8,7 @@
{% trans "Status" %}:
{% trans motion.state.name %}
-
+
{% with motion.polls.all as polls %}
{% if polls.exists and polls.0.has_votes %}
{% for poll in polls reversed %}
@@ -19,12 +19,12 @@
{% trans "Poll result" %}:
{% endif %}
{% with poll.get_options.0 as option %}
-
+
{{ option.Yes }}
{{ option.No }}
{{ option.Abstain }}
{% if poll.votesvalid != None or poll.votesinvalid != None %}
-
+
{% if poll.votesvalid != None %}
{{ poll.print_votesvalid }}
{% endif %}
@@ -33,14 +33,14 @@
{% endif %}
{% endif %}
{% if poll.votescast != None %}
-
+
{{ poll.print_votescast }}
{% endif %}
{% endwith %}
{% else %}
{% if poll|length == 1 %}
-
{% trans "No poll results available." %}
+
{% trans "No result available." %}
{% endif %}
{% endif %}
{% endfor %}
diff --git a/openslides/motion/urls.py b/openslides/motion/urls.py
index 81d02ed0c..af8085b03 100644
--- a/openslides/motion/urls.py
+++ b/openslides/motion/urls.py
@@ -52,19 +52,19 @@ urlpatterns = patterns(
url(r'^(?P
\d+)/create_poll/$',
'poll_create',
- name='motion_poll_create'),
+ name='motionpoll_create'),
url(r'^(?P\d+)/poll/(?P\d+)/edit/$',
'poll_update',
- name='motion_poll_update'),
+ name='motionpoll_update'),
url(r'^(?P\d+)/poll/(?P\d+)/del/$',
'poll_delete',
- name='motion_poll_delete'),
+ name='motionpoll_delete'),
url(r'^(?P\d+)/poll/(?P\d+)/pdf/$',
'poll_pdf',
- name='motion_poll_pdf'),
+ name='motionpoll_pdf'),
url(r'^(?P\d+)/set_state/(?P\d+)/$',
'set_state',
diff --git a/openslides/motion/views.py b/openslides/motion/views.py
index ec547d313..7b1432780 100644
--- a/openslides/motion/views.py
+++ b/openslides/motion/views.py
@@ -483,7 +483,7 @@ class PollCreateView(SingleObjectMixin, RedirectView):
"""
permission_required = 'motion.can_manage_motion'
model = Motion
- url_name = 'motion_poll_detail'
+ url_name = 'motionpoll_detail'
def get(self, request, *args, **kwargs):
"""
@@ -504,7 +504,7 @@ class PollCreateView(SingleObjectMixin, RedirectView):
"""
Return the URL to the UpdateView of the poll.
"""
- return reverse('motion_poll_update', args=[self.object.pk, self.poll.poll_number])
+ return reverse('motionpoll_update', args=[self.object.pk, self.poll.poll_number])
poll_create = PollCreateView.as_view()
@@ -545,7 +545,7 @@ class PollUpdateView(PollMixin, PollFormView):
Poll Class to use for this view.
"""
- template_name = 'motion/poll_form.html'
+ template_name = 'motion/motionpoll_form.html'
def get_context_data(self, **kwargs):
"""
diff --git a/openslides/poll/models.py b/openslides/poll/models.py
index b5f8014d3..cd5bd7d1b 100644
--- a/openslides/poll/models.py
+++ b/openslides/poll/models.py
@@ -36,7 +36,7 @@ class BaseOption(models.Model):
try:
return self.get_votes().get(value=name)
except self.get_vote_class().DoesNotExist:
- return None
+ raise KeyError
class BaseVote(models.Model):
diff --git a/openslides/projector/static/css/projector.css b/openslides/projector/static/css/projector.css
index b2370afc0..e1a29d990 100644
--- a/openslides/projector/static/css/projector.css
+++ b/openslides/projector/static/css/projector.css
@@ -53,7 +53,7 @@ body{
background: url(../img/glyphicons_054_clock_big.png) no-repeat scroll 0px 0px;
}
-/*** CONTENT with base style elements***/
+/*** CONTENT with base style elements ***/
#content {
position: absolute;
left: 75px;
@@ -104,11 +104,21 @@ li {
.well h4.first {
margin-top: 0;
}
-.resultline {
+.well .result {
+ line-height: 30px;
+}
+.well .result hr {
border-top: 1px solid;
margin: 5px 0;
width: 10em;
}
+.result.big {
+ font-size: 120%;
+ line-height: 40px;
+}
+.result .bold {
+ font-weight: bold;
+}
hr {
margin: 10px 0;
}
@@ -187,6 +197,6 @@ tr.total td {
border-top: 1px solid #333333;
background-color: #e3e3e3;
}
-td.elected {
+tr.elected td {
background-color: #BED4DE !important;
}