comparison libervia/backend/tools/common/template_xmlui.py @ 4071:4b842c1fb686

refactoring: renamed `sat` package to `libervia.backend`
author Goffi <goffi@goffi.org>
date Fri, 02 Jun 2023 11:49:51 +0200
parents sat/tools/common/template_xmlui.py@524856bd7b19
children 26b7ed2817da
comparison
equal deleted inserted replaced
4070:d10748475025 4071:4b842c1fb686
1 #!/usr/bin/env python3
2
3
4 # SAT: a jabber client
5 # Copyright (C) 2009-2021 Jérôme Poisson (goffi@goffi.org)
6
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
16
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 """ template XMLUI parsing
21
22 XMLUI classes from this modules can then be iterated to create the template
23 """
24
25 from functools import partial
26 from libervia.backend.core.log import getLogger
27 from sat_frontends.tools import xmlui
28 from sat_frontends.tools import jid
29 try:
30 from jinja2 import Markup as safe
31 except ImportError:
32 # Safe marks XHTML values as usable as it.
33 # If jinja2 is not there, we can use a simple lamba
34 safe = lambda x: x
35
36
37 log = getLogger(__name__)
38
39
40 ## Widgets ##
41
42
43 class Widget(object):
44 category = "widget"
45 type = None
46 enabled = True
47 read_only = True
48
49 def __init__(self, xmlui_parent):
50 self.xmlui_parent = xmlui_parent
51
52 @property
53 def name(self):
54 return self._xmlui_name
55
56
57 class ValueWidget(Widget):
58 def __init__(self, xmlui_parent, value):
59 super(ValueWidget, self).__init__(xmlui_parent)
60 self.value = value
61
62 @property
63 def values(self):
64 return [self.value]
65
66 @property
67 def labels(self):
68 #  helper property, there is not label for ValueWidget
69 # but using labels make rendering more easy (one single method to call)
70 #  values are actually returned
71 return [self.value]
72
73
74 class InputWidget(ValueWidget):
75 def __init__(self, xmlui_parent, value, read_only=False):
76 super(InputWidget, self).__init__(xmlui_parent, value)
77 self.read_only = read_only
78
79
80 class OptionsWidget(Widget):
81 def __init__(self, xmlui_parent, options, selected, style):
82 super(OptionsWidget, self).__init__(xmlui_parent)
83 self.options = options
84 self.selected = selected
85 self.style = style
86
87 @property
88 def values(self):
89 for value, label in self.items:
90 yield value
91
92 @property
93 def value(self):
94 if self.multi or self.no_select or len(self.selected) != 1:
95 raise ValueError(
96 "Can't get value for list with multiple selections or nothing selected"
97 )
98 return self.selected[0]
99
100 @property
101 def labels(self):
102 """return only labels from self.items"""
103 for value, label in self.items:
104 yield label
105
106 @property
107 def items(self):
108 """return suitable items, according to style"""
109 no_select = self.no_select
110 for value, label in self.options:
111 if no_select or value in self.selected:
112 yield value, label
113
114 @property
115 def inline(self):
116 return "inline" in self.style
117
118 @property
119 def no_select(self):
120 return "noselect" in self.style
121
122 @property
123 def multi(self):
124 return "multi" in self.style
125
126
127 class EmptyWidget(xmlui.EmptyWidget, Widget):
128 def __init__(self, _xmlui_parent):
129 Widget.__init__(self)
130
131
132 class TextWidget(xmlui.TextWidget, ValueWidget):
133 type = "text"
134
135
136 class JidWidget(xmlui.JidWidget, ValueWidget):
137 type = "jid"
138
139 def __init__(self, xmlui_parent, value):
140 self.value = jid.JID(value)
141
142
143 class LabelWidget(xmlui.LabelWidget, ValueWidget):
144 type = "label"
145
146 @property
147 def for_name(self):
148 try:
149 return self._xmlui_for_name
150 except AttributeError:
151 return None
152
153
154 class StringWidget(xmlui.StringWidget, InputWidget):
155 type = "string"
156
157
158 class JidInputWidget(xmlui.JidInputWidget, StringWidget):
159 type = "jid"
160
161 class TextBoxWidget(xmlui.TextWidget, InputWidget):
162 type = "textbox"
163
164
165 class XHTMLBoxWidget(xmlui.XHTMLBoxWidget, InputWidget):
166 type = "xhtmlbox"
167
168 def __init__(self, xmlui_parent, value, read_only=False):
169 # XXX: XHTMLBoxWidget value must be cleaned (harmful XHTML must be removed)
170 # This is normally done in the backend, the frontends should not need to
171 # worry about it.
172 super(XHTMLBoxWidget, self).__init__(
173 xmlui_parent=xmlui_parent, value=safe(value), read_only=read_only)
174
175
176 class ListWidget(xmlui.ListWidget, OptionsWidget):
177 type = "list"
178
179
180 ## Containers ##
181
182
183 class Container(object):
184 category = "container"
185 type = None
186
187 def __init__(self, xmlui_parent):
188 self.xmlui_parent = xmlui_parent
189 self.children = []
190
191 def __iter__(self):
192 return iter(self.children)
193
194 def _xmlui_append(self, widget):
195 self.children.append(widget)
196
197 def _xmlui_remove(self, widget):
198 self.children.remove(widget)
199
200
201 class VerticalContainer(xmlui.VerticalContainer, Container):
202 type = "vertical"
203
204
205 class PairsContainer(xmlui.PairsContainer, Container):
206 type = "pairs"
207
208
209 class LabelContainer(xmlui.PairsContainer, Container):
210 type = "label"
211
212
213 ## Factory ##
214
215
216 class WidgetFactory(object):
217
218 def __getattr__(self, attr):
219 if attr.startswith("create"):
220 cls = globals()[attr[6:]]
221 return cls
222
223
224 ## Core ##
225
226
227 class XMLUIPanel(xmlui.XMLUIPanel):
228 widget_factory = WidgetFactory()
229
230 def show(self, *args, **kwargs):
231 raise NotImplementedError
232
233
234 class XMLUIDialog(xmlui.XMLUIDialog):
235 dialog_factory = WidgetFactory()
236
237 def __init__(*args, **kwargs):
238 raise NotImplementedError
239
240
241 create = partial(xmlui.create, class_map={
242 xmlui.CLASS_PANEL: XMLUIPanel,
243 xmlui.CLASS_DIALOG: XMLUIDialog})