1#!/usr/bin/env python3
2
3"""Display information about XML Reporting widgets."""
4
5from collections import OrderedDict
6
7from django.urls import reverse
8from django.shortcuts import render
9from django.views.decorators.cache import cache_page # , never_cache
10from django.http import Http404
11from docutils.core import publish_parts
12from django.utils.safestring import mark_safe
13
14from chart.project import settings
15from chart.reports.widget import widget_classes
16from chart.common import traits
17from chart.common.prettyprint import Table
18from chart.common.decorators import memoized
19
20
21def safe_rst_module_docstring(mod):
22 """Convert the docstring of `mod` into html via a restructredtext parser."""
23 docstring = getattr(mod, '__doc__', '')
24 if docstring is None:
25 docstring='no docstring provided'
26 joined = ' '.join(docstring.split('\n')).strip()
27 rst = publish_parts(source=joined,
28 writer_name='html4css1')['fragment']
29 return mark_safe(rst)
30
31
32@memoized
33def widget_info():
34 """Return widget infomation as a dictionary (core, proj) of lists of widgets.
35 Each widget is a dictionary of metadata."""
36 result = {}
37 for widget_dir in settings.WIDGET_DIRS:
38 # Allow dirs (like the digest dir) to be hidden from the gallery
39 if not widget_dir.get('show-in-gallery', True):
40 continue
41
42 classes = widget_classes(widget_dir['dir'])
43 widget_infos = []
44 for widget_name in sorted(classes.keys()):
45 widget_class = classes[widget_name]
46 widget_infos.append({'name': widget_class.name,
47 'description': safe_rst_module_docstring(widget_class),
48 'thumbnail': getattr(widget_class, 'thumbnail', None),
49 'image': getattr(widget_class, 'image', None),
50 'url': reverse('widgets:single', kwargs=dict(widget_name=widget_name))})
51
52 result[widget_dir['name']] = widget_infos
53
54 return result
55
56
57@cache_page(86400 * 365)
58def index(request): # (unused arg) pylint: disable=W0613
59 """Display list of all available built-in widgets."""
60 return render(request,
61 'widgets/widgets.html',
62 {'widgets': widget_info()})
63
64
65def html_options(options, choices, unit):
66 """Convert a widget `options` field into a table showing available options.
67
68 Recursive.
69 """
70 if options is None:
71 return '<p>No configuration options</p>'
72
73 if isinstance(options, list):
74 t = Table(headings=('Name', 'Description', 'Quantisation', 'Default', 'Type'),
75 cssclass='table table-striped table-bordered')
76 for o in options:
77 if o.multiple:
78 quantisation = 'multiple'
79
80 else:
81 if o.optional:
82 quantisation = 'optional'
83
84 else:
85 quantisation = 'required'
86
87 t.append(('<b>' + o.name + '</b>',
88 o.description,
89 quantisation,
90 o.default,
91 html_options(o.datatype, o.choices, o.unit)))
92
93 return t.to_html_str()
94
95 else:
96 if choices is not None:
97 l = []
98 for c in choices:
99 if c.description is not None:
100 l.append('"{name}" ({desc})'.format(name=c.name, desc=c.description))
101
102 else:
103 l.append('"{name}"'.format(name=c.name))
104
105 return 'string, select from:<ul><li>' + '</li><li>'.join(l) + '</li></ul>'
106
107 # print 'determining choices options ', options, ' x ', choices
108 # res = traits.traitname(options)
109 res = options.value
110
111 if unit is not None:
112 res = res + ' <span title="unit">({unit})</span>'.format(unit=unit)
113
114 tooltip = None # traits.traittooltip(options)
115 if tooltip is not None:
116 res = "<span title='{tooltip}'>{res}</span>".format(tooltip=tooltip, res=res)
117
118 return res
119
120
121def view_widget(request, widget_name):
122 """Display information about a single widget."""
123 for widget_dir in settings.WIDGET_DIRS:
124 w = widget_classes(widget_dir['dir']).get(widget_name)
125 if w is not None:
126 break
127
128 if w is None:
129 raise Http404('Widget {name} not found'.format(name=widget_name))
130
131 example = '<{name}>\n option 1\n option 2\n ...\n</{name}>'.format(name=w.name)
132
133 # force the ordereddict to list converter in the Widget constructor to run
134 dummy = w()
135
136 return render(request,
137 'widgets/widget.html',
138 dict(name=widget_name,
139 options=html_options(w.options, None, None),
140 doc=safe_rst_module_docstring(w),
141 widget=w,
142 example=example))