2013-11-14 01:16:14 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
from django.core.urlresolvers import reverse
|
|
|
|
from django.dispatch import Signal
|
|
|
|
from django.template import RequestContext
|
|
|
|
from django.template.loader import render_to_string
|
|
|
|
|
|
|
|
from .dispatch import SignalConnectMetaClass
|
|
|
|
|
|
|
|
|
|
|
|
class Widget(object):
|
|
|
|
"""
|
|
|
|
Base class for a widget for the dashboard.
|
|
|
|
|
2013-12-09 23:56:01 +01:00
|
|
|
Every app which wants to add widgets to the dashboard has to create a
|
2013-11-14 01:16:14 +01:00
|
|
|
widget class subclassing from this base class. The name attribute has to
|
2014-05-06 13:21:46 +02:00
|
|
|
be set. It has to be unique. The __metaclass__ attribute
|
|
|
|
(SignalConnectMetaClass) does the rest of the magic.
|
2013-11-14 01:16:14 +01:00
|
|
|
|
2014-05-06 13:21:46 +02:00
|
|
|
For the appearance of the widget there are some attributes and methods
|
2014-05-15 20:07:09 +02:00
|
|
|
like verbose_name, required_permission, default_column, default_weight,
|
2013-12-09 23:56:01 +01:00
|
|
|
default_active, template_name, context, icon_css_class,
|
2014-05-06 13:21:46 +02:00
|
|
|
more_link_pattern_name, stylesheets, javascript_files,
|
|
|
|
get_verbose_name, check_permission, get_html, get_context_data,
|
|
|
|
get_icon_css_class, get_url_for_more, get_stylesheets and
|
|
|
|
get_javascript_files. Most of them are optional.
|
2013-11-14 01:16:14 +01:00
|
|
|
"""
|
|
|
|
__metaclass__ = SignalConnectMetaClass
|
|
|
|
signal = Signal(providing_args=['request'])
|
|
|
|
name = None
|
|
|
|
verbose_name = None
|
2014-05-15 20:07:09 +02:00
|
|
|
required_permission = None
|
2013-11-14 01:16:14 +01:00
|
|
|
default_column = 1
|
|
|
|
default_weight = 0
|
|
|
|
default_active = True
|
|
|
|
template_name = None
|
|
|
|
context = None
|
|
|
|
icon_css_class = None
|
|
|
|
more_link_pattern_name = None
|
|
|
|
stylesheets = None
|
|
|
|
javascript_files = None
|
|
|
|
|
|
|
|
def __init__(self, sender, request, **kwargs):
|
|
|
|
"""
|
2013-12-09 23:56:01 +01:00
|
|
|
Initializes the widget instance. This is done when the signal is sent.
|
2013-11-14 01:16:14 +01:00
|
|
|
|
|
|
|
Only the required request argument is used. Because of Django's signal
|
|
|
|
API, we have to take also a sender argument and wildcard keyword
|
|
|
|
arguments. But they are not used here.
|
|
|
|
"""
|
|
|
|
self.request = request
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return repr(self.get_verbose_name())
|
|
|
|
|
|
|
|
def __unicode__(self):
|
|
|
|
return unicode(self.get_verbose_name())
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_dispatch_uid(cls):
|
|
|
|
"""
|
|
|
|
Returns the name as a unique string for each class. Returns None for
|
|
|
|
the base class so it will not be connected to the signal.
|
2014-05-06 13:21:46 +02:00
|
|
|
|
|
|
|
This does not follow the example implementation of
|
|
|
|
SignalConnectMetaClass, so take care here.
|
2013-11-14 01:16:14 +01:00
|
|
|
"""
|
|
|
|
return cls.name
|
|
|
|
|
|
|
|
def get_verbose_name(self):
|
|
|
|
"""
|
|
|
|
Returns a human readable name of the widget.
|
|
|
|
"""
|
|
|
|
return self.verbose_name or self.name.capitalize()
|
|
|
|
|
|
|
|
def check_permission(self):
|
|
|
|
"""
|
|
|
|
Returns True if the request user is allowed to see the widget.
|
|
|
|
"""
|
2014-05-15 20:07:09 +02:00
|
|
|
return self.required_permission is None or self.request.user.has_perm(self.required_permission)
|
2013-11-14 01:16:14 +01:00
|
|
|
|
|
|
|
def is_active(self):
|
|
|
|
"""
|
|
|
|
Returns True if the widget is active to be displayed.
|
|
|
|
"""
|
|
|
|
session_widgets = self.request.session.get('widgets', {})
|
|
|
|
return session_widgets.get(self.name, self.default_active)
|
|
|
|
|
|
|
|
def get_html(self):
|
|
|
|
"""
|
|
|
|
Returns the html code of the widget.
|
|
|
|
|
|
|
|
This method also adds the widget itself to the context.
|
|
|
|
"""
|
|
|
|
if self.template_name is not None:
|
|
|
|
html = render_to_string(
|
|
|
|
template_name=self.template_name,
|
|
|
|
dictionary=self.get_context_data(widget=self),
|
|
|
|
context_instance=RequestContext(self.request))
|
|
|
|
else:
|
|
|
|
raise NotImplementedError('A widget class must define either a get_html '
|
|
|
|
'method or have template_name argument.')
|
|
|
|
return html
|
|
|
|
|
|
|
|
def get_context_data(self, **context):
|
|
|
|
"""
|
|
|
|
Returns the context data for the widget template.
|
|
|
|
"""
|
|
|
|
return_context = self.context or {}
|
|
|
|
return_context.update(context)
|
|
|
|
return return_context
|
|
|
|
|
|
|
|
def get_icon_css_class(self):
|
|
|
|
"""
|
|
|
|
Returns the css class name of the icon.
|
|
|
|
"""
|
|
|
|
return self.icon_css_class or 'icon-%s' % self.name
|
|
|
|
|
|
|
|
def get_url_for_more(self):
|
|
|
|
"""
|
|
|
|
Returns the url for the link 'More ...' in the base template.
|
|
|
|
"""
|
|
|
|
if self.more_link_pattern_name is not None:
|
|
|
|
url = reverse(self.more_link_pattern_name)
|
|
|
|
else:
|
|
|
|
url = None
|
|
|
|
return url
|
|
|
|
|
|
|
|
def get_stylesheets(self):
|
|
|
|
"""
|
|
|
|
Returns an interable of stylesheets to be loaded.
|
|
|
|
"""
|
|
|
|
return iter(self.stylesheets or [])
|
|
|
|
|
|
|
|
def get_javascript_files(self):
|
|
|
|
"""
|
|
|
|
Returns an interable of javascript files to be loaded.
|
|
|
|
"""
|
|
|
|
return iter(self.javascript_files or [])
|