2012-04-25 22:29:19 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
2013-11-06 14:42:14 +01:00
|
|
|
from json import dumps
|
2013-10-07 08:52:18 +02:00
|
|
|
from time import time
|
2013-08-04 12:59:11 +02:00
|
|
|
|
2013-09-25 10:01:01 +02:00
|
|
|
from django.template.loader import render_to_string
|
2012-02-03 23:12:28 +01:00
|
|
|
|
2013-03-01 17:13:12 +01:00
|
|
|
from openslides.config.api import config
|
2013-08-04 12:59:11 +02:00
|
|
|
from openslides.utils.tornado_webserver import ProjectorSocketHandler
|
2013-11-08 08:33:01 +01:00
|
|
|
from openslides.utils.exceptions import OpenSlidesError
|
2013-08-04 12:59:11 +02:00
|
|
|
|
2013-09-25 10:01:01 +02:00
|
|
|
from .signals import projector_overlays
|
2012-06-11 13:43:48 +02:00
|
|
|
|
2013-08-04 12:59:11 +02:00
|
|
|
slide_callback = {}
|
|
|
|
"""
|
|
|
|
A dictonary where the key is the name of a slide, and the value is a
|
|
|
|
callable object which returns the html code for a slide.
|
|
|
|
"""
|
2012-02-03 23:12:28 +01:00
|
|
|
|
2013-11-24 17:19:14 +01:00
|
|
|
slide_model = {}
|
|
|
|
"""
|
|
|
|
A dictonary for SlideMixin models to reference from the slide_callback_name to
|
|
|
|
the Model
|
|
|
|
"""
|
|
|
|
# TODO: Find a bether way to do this. Maybe by reimplementing slides with
|
|
|
|
# metaclasses
|
|
|
|
|
2013-08-04 12:59:11 +02:00
|
|
|
|
2013-11-08 08:33:01 +01:00
|
|
|
class SlideError(OpenSlidesError):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2013-08-04 12:59:11 +02:00
|
|
|
def update_projector():
|
2012-07-07 14:01:40 +02:00
|
|
|
"""
|
2013-08-04 12:59:11 +02:00
|
|
|
Sends the data to the clients, who listen to the projector.
|
2012-07-07 14:01:40 +02:00
|
|
|
"""
|
2013-08-04 12:59:11 +02:00
|
|
|
# TODO: only send necessary html
|
|
|
|
ProjectorSocketHandler.send_updates({'content': get_projector_content()})
|
2012-02-03 23:12:28 +01:00
|
|
|
|
|
|
|
|
2013-08-04 12:59:11 +02:00
|
|
|
def update_projector_overlay(overlay):
|
2012-07-07 14:01:40 +02:00
|
|
|
"""
|
2013-10-03 21:49:51 +02:00
|
|
|
Update one or all overlay on the projector.
|
2013-08-04 12:59:11 +02:00
|
|
|
|
|
|
|
Checks if the overlay is activated and updates it in this case.
|
|
|
|
|
2013-10-03 21:49:51 +02:00
|
|
|
The argument 'overlay' has to be an overlay object, the name of a
|
|
|
|
ovleray or None. If it is None, all overlays will be updated.
|
2012-07-07 14:01:40 +02:00
|
|
|
"""
|
2013-08-04 12:59:11 +02:00
|
|
|
if overlay is None:
|
2013-09-25 10:01:01 +02:00
|
|
|
overlays = [item for item in get_overlays().values()]
|
2013-10-03 21:49:51 +02:00
|
|
|
elif isinstance(overlay, basestring):
|
|
|
|
overlays = [get_overlays()[overlay]]
|
2013-08-04 12:59:11 +02:00
|
|
|
else:
|
|
|
|
overlays = [overlay]
|
|
|
|
|
|
|
|
overlay_dict = {}
|
|
|
|
for overlay in overlays:
|
|
|
|
if overlay.is_active():
|
|
|
|
overlay_dict[overlay.name] = {
|
|
|
|
'html': overlay.get_projector_html(),
|
|
|
|
'javascript': overlay.get_javascript()}
|
|
|
|
else:
|
|
|
|
overlay_dict[overlay.name] = None
|
|
|
|
ProjectorSocketHandler.send_updates({'overlays': overlay_dict})
|
|
|
|
|
|
|
|
|
2013-10-17 15:32:54 +02:00
|
|
|
def call_on_projector(calls):
|
|
|
|
"""
|
|
|
|
Sends data to the projector.
|
2013-10-29 18:28:05 +01:00
|
|
|
|
|
|
|
The argument call has to be a dictionary with the javascript function name
|
|
|
|
as key and the argument for it as value.
|
2013-10-17 15:32:54 +02:00
|
|
|
"""
|
|
|
|
projector_js_cache = config['projector_js_cache']
|
|
|
|
projector_js_cache.update(calls)
|
|
|
|
config['projector_js_cache'] = projector_js_cache
|
2013-10-28 21:17:32 +01:00
|
|
|
ProjectorSocketHandler.send_updates({'calls': calls})
|
2013-10-17 15:32:54 +02:00
|
|
|
|
|
|
|
|
2013-08-04 12:59:11 +02:00
|
|
|
def get_projector_content(slide_dict=None):
|
|
|
|
"""
|
2013-10-29 18:28:05 +01:00
|
|
|
Returns the HTML-Content block for the projector.
|
|
|
|
|
|
|
|
Slide_dict has to be an dictonary with the key 'callback'.
|
|
|
|
|
|
|
|
If slide_dict is None, use the active slide from the database.
|
2013-08-04 12:59:11 +02:00
|
|
|
"""
|
|
|
|
if slide_dict is None:
|
|
|
|
slide_dict = config['projector_active_slide'].copy()
|
|
|
|
callback = slide_dict.pop('callback', None)
|
2012-04-17 12:07:32 +02:00
|
|
|
|
2012-04-16 16:35:30 +02:00
|
|
|
try:
|
2013-10-29 18:28:05 +01:00
|
|
|
slide_content = slide_callback[callback](**slide_dict)
|
2013-11-08 08:33:01 +01:00
|
|
|
except (KeyError, SlideError):
|
2013-10-29 18:28:05 +01:00
|
|
|
slide_content = default_slide()
|
|
|
|
return slide_content
|
2012-04-16 16:35:30 +02:00
|
|
|
|
|
|
|
|
2013-08-04 12:59:11 +02:00
|
|
|
def default_slide():
|
|
|
|
"""
|
|
|
|
Returns the HTML Code for the default slide.
|
2012-02-03 23:12:28 +01:00
|
|
|
"""
|
2013-08-04 12:59:11 +02:00
|
|
|
return render_to_string('projector/default_slide.html')
|
2012-02-03 23:12:28 +01:00
|
|
|
|
2013-08-04 12:59:11 +02:00
|
|
|
|
|
|
|
def get_overlays():
|
2012-02-03 23:12:28 +01:00
|
|
|
"""
|
2013-08-04 12:59:11 +02:00
|
|
|
Returns all overlay objects.
|
2012-02-03 23:12:28 +01:00
|
|
|
|
2013-08-04 12:59:11 +02:00
|
|
|
The returned value is a dictonary with the name of the overlay as key, and
|
|
|
|
the overlay object as value.
|
|
|
|
"""
|
|
|
|
overlays = {}
|
|
|
|
for receiver, overlay in projector_overlays.send(sender='get_overlays'):
|
|
|
|
overlays[overlay.name] = overlay
|
|
|
|
return overlays
|
2012-02-03 23:12:28 +01:00
|
|
|
|
|
|
|
|
2013-08-04 12:59:11 +02:00
|
|
|
def get_projector_overlays():
|
2012-07-07 14:01:40 +02:00
|
|
|
"""
|
2013-08-04 12:59:11 +02:00
|
|
|
Returns the HTML code for all active overlays.
|
2012-07-07 14:01:40 +02:00
|
|
|
"""
|
2013-08-04 12:59:11 +02:00
|
|
|
overlays = [{'name': key, 'html': overlay.get_projector_html()}
|
|
|
|
for key, overlay in get_overlays().items()
|
|
|
|
if overlay.is_active()]
|
|
|
|
return render_to_string('projector/all_overlays.html', {'overlays': overlays})
|
2012-10-29 23:26:10 +01:00
|
|
|
|
|
|
|
|
2013-11-06 14:42:14 +01:00
|
|
|
def get_projector_overlays_js(as_json=False):
|
2013-08-04 12:59:11 +02:00
|
|
|
"""
|
2013-10-29 18:28:05 +01:00
|
|
|
Returns JS-Code for the active overlays.
|
2012-02-09 02:29:38 +01:00
|
|
|
|
2013-08-04 12:59:11 +02:00
|
|
|
The retuned value is a list of json objects.
|
|
|
|
"""
|
2013-09-25 10:01:01 +02:00
|
|
|
javascript = []
|
|
|
|
for overlay in get_overlays().values():
|
2013-08-04 12:59:11 +02:00
|
|
|
if overlay.is_active():
|
|
|
|
overlay_js = overlay.get_javascript()
|
|
|
|
if overlay_js:
|
2013-11-06 14:42:14 +01:00
|
|
|
if as_json:
|
|
|
|
overlay_js = dumps(overlay_js)
|
2013-10-28 21:17:32 +01:00
|
|
|
javascript.append(overlay_js)
|
2013-09-25 10:01:01 +02:00
|
|
|
return javascript
|
2012-02-09 02:29:38 +01:00
|
|
|
|
2013-08-04 12:59:11 +02:00
|
|
|
|
2013-11-24 17:19:14 +01:00
|
|
|
def register_slide(name, callback, model=None):
|
2013-08-04 12:59:11 +02:00
|
|
|
"""
|
2013-11-24 17:19:14 +01:00
|
|
|
Registers a function as slide callback.
|
|
|
|
|
|
|
|
The optional argument 'model' is used to register a SlideModelClass.
|
2012-07-07 14:01:40 +02:00
|
|
|
"""
|
2013-08-04 12:59:11 +02:00
|
|
|
slide_callback[name] = callback
|
2013-11-24 17:19:14 +01:00
|
|
|
if model is not None:
|
|
|
|
slide_model[name] = model
|
2013-08-04 12:59:11 +02:00
|
|
|
|
|
|
|
|
2013-10-03 21:49:51 +02:00
|
|
|
def register_slide_model(SlideModel, template):
|
|
|
|
"""
|
|
|
|
Shortcut for register_slide for a Model with the SlideMixin.
|
|
|
|
|
|
|
|
The Argument 'SlideModel' has to be a Django-Model-Class, which is a subclass
|
|
|
|
of SlideMixin. Template has to be a string to the path of a template.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def model_slide(**kwargs):
|
|
|
|
"""
|
|
|
|
Return the html code for the model slide.
|
|
|
|
"""
|
|
|
|
slide_pk = kwargs.get('pk', None)
|
|
|
|
|
|
|
|
try:
|
|
|
|
slide = SlideModel.objects.get(pk=slide_pk)
|
|
|
|
except SlideModel.DoesNotExist:
|
2013-11-08 08:33:01 +01:00
|
|
|
raise SlideError
|
2013-10-03 21:49:51 +02:00
|
|
|
else:
|
|
|
|
context = slide.get_slide_context()
|
|
|
|
|
|
|
|
return render_to_string(template, context)
|
|
|
|
|
2013-11-24 17:19:14 +01:00
|
|
|
register_slide(SlideModel.slide_callback_name, model_slide, SlideModel)
|
2013-10-03 21:49:51 +02:00
|
|
|
|
|
|
|
|
2013-11-22 18:18:06 +01:00
|
|
|
def set_active_slide(callback, **kwargs):
|
2012-07-07 14:01:40 +02:00
|
|
|
"""
|
2013-08-04 12:59:11 +02:00
|
|
|
Set the active Slide.
|
2012-04-14 11:18:47 +02:00
|
|
|
|
2013-08-04 12:59:11 +02:00
|
|
|
callback: The name of the slide callback.
|
|
|
|
kwargs: Keyword arguments for the slide callback.
|
|
|
|
"""
|
|
|
|
kwargs.update(callback=callback)
|
|
|
|
config['projector_active_slide'] = kwargs
|
|
|
|
update_projector()
|
|
|
|
update_projector_overlay(None)
|
2012-02-03 23:12:28 +01:00
|
|
|
|
|
|
|
|
2013-08-04 12:59:11 +02:00
|
|
|
def get_active_slide():
|
2012-07-07 14:01:40 +02:00
|
|
|
"""
|
2013-10-03 21:49:51 +02:00
|
|
|
Returns the dictonary, which defines the active slide.
|
2012-07-07 14:01:40 +02:00
|
|
|
"""
|
2013-08-04 12:59:11 +02:00
|
|
|
return config['projector_active_slide']
|
2012-04-16 16:35:30 +02:00
|
|
|
|
|
|
|
|
2013-11-24 17:19:14 +01:00
|
|
|
def get_active_object():
|
|
|
|
"""
|
|
|
|
Returns an object if the active slide is an instance of SlideMixin.
|
|
|
|
In other case, returns None
|
|
|
|
"""
|
|
|
|
active_slide_dict = get_active_slide()
|
|
|
|
callback_name = active_slide_dict.get('callback', None)
|
|
|
|
object_pk = active_slide_dict.get('pk', None)
|
|
|
|
try:
|
|
|
|
Model = slide_model[callback_name]
|
|
|
|
except KeyError:
|
|
|
|
value = None
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
value = Model.objects.get(pk=object_pk)
|
|
|
|
except Model.DoesNotExist:
|
|
|
|
value = None
|
|
|
|
return value
|
|
|
|
|
|
|
|
|
2013-10-07 08:52:18 +02:00
|
|
|
def start_countdown():
|
|
|
|
"""
|
|
|
|
Starts the countdown
|
|
|
|
"""
|
|
|
|
# if we had stopped the countdown resume were we left of
|
|
|
|
if config['countdown_state'] == 'paused':
|
|
|
|
start_stamp = config['countdown_start_stamp']
|
|
|
|
pause_stamp = config['countdown_pause_stamp']
|
|
|
|
now = time()
|
|
|
|
config['countdown_start_stamp'] = now - \
|
|
|
|
(pause_stamp - start_stamp)
|
|
|
|
else:
|
|
|
|
config['countdown_start_stamp'] = time()
|
|
|
|
|
|
|
|
config['countdown_state'] = 'active'
|
|
|
|
config['countdown_pause_stamp'] = 0
|
|
|
|
|
|
|
|
|
|
|
|
def stop_countdown():
|
|
|
|
"""
|
|
|
|
Stops the countdown
|
|
|
|
"""
|
|
|
|
if config['countdown_state'] == 'active':
|
|
|
|
config['countdown_state'] = 'paused'
|
|
|
|
config['countdown_pause_stamp'] = time()
|
|
|
|
|
|
|
|
|
|
|
|
def reset_countdown():
|
|
|
|
"""
|
|
|
|
Resets the countdown
|
|
|
|
"""
|
|
|
|
config['countdown_start_stamp'] = time()
|
|
|
|
config['countdown_pause_stamp'] = 0
|
|
|
|
config['countdown_state'] = 'inactive'
|