comparison sat_frontends/jp/xmlui_manager.py @ 3568:04283582966f

core, frontends: fix invalid translatable strings. Some f-strings where used in translatable text, this has been fixed by using explicit `format()` call (using a script based on `tokenize`). As tokenize messes with spaces, a reformating tool (`black`) has been applied to some files afterwards.
author Goffi <goffi@goffi.org>
date Mon, 14 Jun 2021 18:35:12 +0200
parents be6d91572633
children 53a8b50d69ca
comparison
equal deleted inserted replaced
3567:a240748ed686 3568:04283582966f
172 def no_select(self): 172 def no_select(self):
173 return "noselect" in self.style 173 return "noselect" in self.style
174 174
175 175
176 class EmptyWidget(xmlui_base.EmptyWidget, Widget): 176 class EmptyWidget(xmlui_base.EmptyWidget, Widget):
177
178 def __init__(self, xmlui_parent): 177 def __init__(self, xmlui_parent):
179 Widget.__init__(self, xmlui_parent) 178 Widget.__init__(self, xmlui_parent)
180 179
181 async def show(self): 180 async def show(self):
182 self.host.disp('') 181 self.host.disp("")
183 182
184 183
185 class TextWidget(xmlui_base.TextWidget, ValueWidget): 184 class TextWidget(xmlui_base.TextWidget, ValueWidget):
186 type = "text" 185 type = "text"
187 186
197 try: 196 try:
198 return self._xmlui_for_name 197 return self._xmlui_for_name
199 except AttributeError: 198 except AttributeError:
200 return None 199 return None
201 200
202 async def show(self, end='\n', ansi=""): 201 async def show(self, end="\n", ansi=""):
203 """show label 202 """show label
204 203
205 @param end(str): same as for [JP.disp] 204 @param end(str): same as for [JP.disp]
206 @param ansi(unicode): ansi escape code to print before label 205 @param ansi(unicode): ansi escape code to print before label
207 """ 206 """
208 self.disp(A.color(ansi, self.value), end=end) 207 self.disp(A.color(ansi, self.value), end=end)
209 208
210 209
211 class JidWidget(xmlui_base.JidWidget, TextWidget): 210 class JidWidget(xmlui_base.JidWidget, TextWidget):
212 type = "jid" 211 type = "jid"
212
213 213
214 class StringWidget(xmlui_base.StringWidget, InputWidget): 214 class StringWidget(xmlui_base.StringWidget, InputWidget):
215 type = "string" 215 type = "string"
216 216
217 async def show(self): 217 async def show(self):
219 self.disp(self.value) 219 self.disp(self.value)
220 else: 220 else:
221 elems = [] 221 elems = []
222 self.verboseName(elems) 222 self.verboseName(elems)
223 if self.value: 223 if self.value:
224 elems.append(_(f"(enter: {self.value})")) 224 elems.append(_("(enter: {value})").format(value=self.value))
225 elems.extend([C.A_HEADER, "> "]) 225 elems.extend([C.A_HEADER, "> "])
226 value = await self.host.ainput(A.color(*elems)) 226 value = await self.host.ainput(A.color(*elems))
227 if value: 227 if value:
228 #  TODO: empty value should be possible 228 #  TODO: empty value should be possible
229 # an escape key should be used for default instead of enter with empty value 229 # an escape key should be used for default instead of enter with empty value
242 self.verboseName() 242 self.verboseName()
243 if self.read_only or self.root.read_only: 243 if self.read_only or self.root.read_only:
244 self.disp(self.value) 244 self.disp(self.value)
245 else: 245 else:
246 if self.value: 246 if self.value:
247 self.disp(A.color(C.A_HEADER, "↓ current value ↓\n", A.FG_CYAN, self.value, 247 self.disp(
248 "")) 248 A.color(C.A_HEADER, "↓ current value ↓\n", A.FG_CYAN, self.value, "")
249 )
249 250
250 values = [] 251 values = []
251 while True: 252 while True:
252 try: 253 try:
253 if not values: 254 if not values:
254 line = await self.host.ainput(A.color(C.A_HEADER, "[Ctrl-D to finish]> ")) 255 line = await self.host.ainput(
256 A.color(C.A_HEADER, "[Ctrl-D to finish]> ")
257 )
255 else: 258 else:
256 line = await self.host.ainput() 259 line = await self.host.ainput()
257 values.append(line) 260 values.append(line)
258 except EOFError: 261 except EOFError:
259 break 262 break
260 263
261 self.value = '\n'.join(values).rstrip() 264 self.value = "\n".join(values).rstrip()
262 265
263 266
264 class XHTMLBoxWidget(xmlui_base.XHTMLBoxWidget, StringWidget): 267 class XHTMLBoxWidget(xmlui_base.XHTMLBoxWidget, StringWidget):
265 type = "xhtmlbox" 268 type = "xhtmlbox"
266 269
267 async def show(self): 270 async def show(self):
268 # FIXME: we use bridge in a blocking way as permitted by python-dbus 271 # FIXME: we use bridge in a blocking way as permitted by python-dbus
269 # this only for now to make it simpler, it must be refactored 272 # this only for now to make it simpler, it must be refactored
270 # to use async when jp will be fully async (expected for 0.8) 273 # to use async when jp will be fully async (expected for 0.8)
271 self.value = await self.host.bridge.syntaxConvert( 274 self.value = await self.host.bridge.syntaxConvert(
272 self.value, C.SYNTAX_XHTML, "markdown", False, self.host.profile) 275 self.value, C.SYNTAX_XHTML, "markdown", False, self.host.profile
276 )
273 await super(XHTMLBoxWidget, self).show() 277 await super(XHTMLBoxWidget, self).show()
274 278
275 279
276 class ListWidget(xmlui_base.ListWidget, OptionsWidget): 280 class ListWidget(xmlui_base.ListWidget, OptionsWidget):
277 type = "list" 281 type = "list"
283 self.disp(self.value) 287 self.disp(self.value)
284 return 288 return
285 if not self.options: 289 if not self.options:
286 return 290 return
287 291
288 # list display 292 # list display
289 self.verboseName() 293 self.verboseName()
290 294
291 for idx, (value, label) in enumerate(self.options): 295 for idx, (value, label) in enumerate(self.options):
292 elems = [] 296 elems = []
293 if not self.root.read_only: 297 if not self.root.read_only:
302 if len(self.options) == 1: 306 if len(self.options) == 1:
303 # we have only one option, no need to ask 307 # we have only one option, no need to ask
304 self.value = self.options[0][0] 308 self.value = self.options[0][0]
305 return 309 return
306 310
307 #  we ask use to choose an option 311 #  we ask use to choose an option
308 choice = None 312 choice = None
309 limit_max = len(self.options) - 1 313 limit_max = len(self.options) - 1
310 while choice is None or choice < 0 or choice > limit_max: 314 while choice is None or choice < 0 or choice > limit_max:
311 choice = await self.host.ainput( 315 choice = await self.host.ainput(
312 A.color(C.A_HEADER, _(f"your choice (0-{limit_max}): ")) 316 A.color(
317 C.A_HEADER,
318 _("your choice (0-{limit_max}): ").format(limit_max=limit_max),
319 )
313 ) 320 )
314 try: 321 try:
315 choice = int(choice) 322 choice = int(choice)
316 except ValueError: 323 except ValueError:
317 choice = None 324 choice = None
326 disp_true = A.color(A.FG_GREEN, "TRUE") 333 disp_true = A.color(A.FG_GREEN, "TRUE")
327 disp_false = A.color(A.FG_RED, "FALSE") 334 disp_false = A.color(A.FG_RED, "FALSE")
328 if self.read_only or self.root.read_only: 335 if self.read_only or self.root.read_only:
329 self.disp(disp_true if self.value else disp_false) 336 self.disp(disp_true if self.value else disp_false)
330 else: 337 else:
331 self.disp(A.color(C.A_HEADER, "0: ", 338 self.disp(
332 disp_false, A.RESET, 339 A.color(
333 " *" if not self.value else "")) 340 C.A_HEADER, "0: ", disp_false, A.RESET, " *" if not self.value else ""
334 self.disp(A.color(C.A_HEADER, "1: ", 341 )
335 disp_true, A.RESET, 342 )
336 " *" if self.value else "")) 343 self.disp(
344 A.color(C.A_HEADER, "1: ", disp_true, A.RESET, " *" if self.value else "")
345 )
337 choice = None 346 choice = None
338 while choice not in ("0", "1"): 347 while choice not in ("0", "1"):
339 elems = [C.A_HEADER, _("your choice (0,1): ")] 348 elems = [C.A_HEADER, _("your choice (0,1): ")]
340 self.verboseName(elems) 349 self.verboseName(elems)
341 choice = await self.host.ainput(A.color(*elems)) 350 choice = await self.host.ainput(A.color(*elems))
343 self.disp("") 352 self.disp("")
344 353
345 def _xmluiGetValue(self): 354 def _xmluiGetValue(self):
346 return C.boolConst(self.value) 355 return C.boolConst(self.value)
347 356
348 357 ## Containers ##
349 ## Containers ##
350 358
351 359
352 class Container(Base): 360 class Container(Base):
353 category = "container" 361 category = "container"
354 362
381 class LabelContainer(xmlui_base.PairsContainer, Container): 389 class LabelContainer(xmlui_base.PairsContainer, Container):
382 type = "label" 390 type = "label"
383 391
384 async def show(self): 392 async def show(self):
385 for child in self.children: 393 for child in self.children:
386 end = '\n' 394 end = "\n"
387 # we check linked widget type 395 # we check linked widget type
388 # to see if we want the label on the same line or not 396 # to see if we want the label on the same line or not
389 if child.type == "label": 397 if child.type == "label":
390 for_name = child.for_name 398 for_name = child.for_name
391 if for_name: 399 if for_name:
394 if self.root.values_only or wid_type in ( 402 if self.root.values_only or wid_type in (
395 "text", 403 "text",
396 "string", 404 "string",
397 "jid_input", 405 "jid_input",
398 ): 406 ):
399 end = ' ' 407 end = " "
400 elif wid_type == "bool" and for_widget.read_only: 408 elif wid_type == "bool" and for_widget.read_only:
401 end = ' ' 409 end = " "
402 await child.show(end=end, ansi=A.FG_CYAN) 410 await child.show(end=end, ansi=A.FG_CYAN)
403 else: 411 else:
404 await child.show() 412 await child.show()
405 413
406 414 ## Dialogs ##
407 ## Dialogs ##
408 415
409 416
410 class Dialog(object): 417 class Dialog(object):
411 def __init__(self, xmlui_parent): 418 def __init__(self, xmlui_parent):
412 self.xmlui_parent = xmlui_parent 419 self.xmlui_parent = xmlui_parent
420 427
421 must be overriden by subclasses 428 must be overriden by subclasses
422 """ 429 """
423 raise NotImplementedError(self.__class__) 430 raise NotImplementedError(self.__class__)
424 431
432
425 class MessageDialog(xmlui_base.MessageDialog, Dialog): 433 class MessageDialog(xmlui_base.MessageDialog, Dialog):
426
427 def __init__(self, xmlui_parent, title, message, level): 434 def __init__(self, xmlui_parent, title, message, level):
428 Dialog.__init__(self, xmlui_parent) 435 Dialog.__init__(self, xmlui_parent)
429 xmlui_base.MessageDialog.__init__(self, xmlui_parent) 436 xmlui_base.MessageDialog.__init__(self, xmlui_parent)
430 self.title, self.message, self.level = title, message, level 437 self.title, self.message, self.level = title, message, level
431 438
435 self.disp(A.color(C.A_HEADER, self.title)) 442 self.disp(A.color(C.A_HEADER, self.title))
436 self.disp(self.message) 443 self.disp(self.message)
437 444
438 445
439 class NoteDialog(xmlui_base.NoteDialog, Dialog): 446 class NoteDialog(xmlui_base.NoteDialog, Dialog):
440
441 def __init__(self, xmlui_parent, title, message, level): 447 def __init__(self, xmlui_parent, title, message, level):
442 Dialog.__init__(self, xmlui_parent) 448 Dialog.__init__(self, xmlui_parent)
443 xmlui_base.NoteDialog.__init__(self, xmlui_parent) 449 xmlui_base.NoteDialog.__init__(self, xmlui_parent)
444 self.title, self.message, self.level = title, message, level 450 self.title, self.message, self.level = title, message, level
445 451
454 msg = self.message 460 msg = self.message
455 self.disp(msg, error=error) 461 self.disp(msg, error=error)
456 462
457 463
458 class ConfirmDialog(xmlui_base.ConfirmDialog, Dialog): 464 class ConfirmDialog(xmlui_base.ConfirmDialog, Dialog):
459
460 def __init__(self, xmlui_parent, title, message, level, buttons_set): 465 def __init__(self, xmlui_parent, title, message, level, buttons_set):
461 Dialog.__init__(self, xmlui_parent) 466 Dialog.__init__(self, xmlui_parent)
462 xmlui_base.ConfirmDialog.__init__(self, xmlui_parent) 467 xmlui_base.ConfirmDialog.__init__(self, xmlui_parent)
463 self.title, self.message, self.level, self.buttons_set = ( 468 self.title, self.message, self.level, self.buttons_set = (
464 title, message, level, buttons_set) 469 title,
470 message,
471 level,
472 buttons_set,
473 )
465 474
466 async def show(self): 475 async def show(self):
467 # TODO: handle buttons_set and level 476 # TODO: handle buttons_set and level
468 self.disp(self.message) 477 self.disp(self.message)
469 if self.title: 478 if self.title:
470 self.disp(A.color(C.A_HEADER, self.title)) 479 self.disp(A.color(C.A_HEADER, self.title))
471 input_ = None 480 input_ = None
472 while input_ not in ('y', 'n'): 481 while input_ not in ("y", "n"):
473 input_ = await self.host.ainput(f"{self.message} (y/n)? ") 482 input_ = await self.host.ainput(f"{self.message} (y/n)? ")
474 input_ = input_.lower() 483 input_ = input_.lower()
475 if input_ == 'y': 484 if input_ == "y":
476 self._xmluiValidated() 485 self._xmluiValidated()
477 else: 486 else:
478 self._xmluiCancelled() 487 self._xmluiCancelled()
479 488
480 489 ## Factory ##
481 ## Factory ##
482 490
483 491
484 class WidgetFactory(object): 492 class WidgetFactory(object):
485 def __getattr__(self, attr): 493 def __getattr__(self, attr):
486 if attr.startswith("create"): 494 if attr.startswith("create"):
494 read_only = False 502 read_only = False
495 values_only = False 503 values_only = False
496 workflow = None 504 workflow = None
497 _submit_cb = None 505 _submit_cb = None
498 506
499 def __init__(self, host, parsed_dom, title=None, flags=None, callback=None, 507 def __init__(
500 ignore=None, whitelist=None, profile=None): 508 self,
509 host,
510 parsed_dom,
511 title=None,
512 flags=None,
513 callback=None,
514 ignore=None,
515 whitelist=None,
516 profile=None,
517 ):
501 xmlui_base.XMLUIPanel.__init__( 518 xmlui_base.XMLUIPanel.__init__(
502 self, 519 self,
503 host, 520 host,
504 parsed_dom, 521 parsed_dom,
505 title=title, 522 title=title,
586 xmlui_raw = data["xmlui"] 603 xmlui_raw = data["xmlui"]
587 xmlui = create(self.host, xmlui_raw) 604 xmlui = create(self.host, xmlui_raw)
588 await xmlui.show() 605 await xmlui.show()
589 if xmlui.submit_id: 606 if xmlui.submit_id:
590 await xmlui.onFormSubmitted() 607 await xmlui.onFormSubmitted()
591 # TODO: handle data other than XMLUI 608 # TODO: handle data other than XMLUI
592 if not XMLUIPanel._actions: 609 if not XMLUIPanel._actions:
593 if self._submit_cb is None: 610 if self._submit_cb is None:
594 self.host.quit() 611 self.host.quit()
595 else: 612 else:
596 self._submit_cb() 613 self._submit_cb()
620 637
621 def _xmluiClose(self): 638 def _xmluiClose(self):
622 pass 639 pass
623 640
624 641
625 create = partial(xmlui_base.create, class_map={ 642 create = partial(
626 xmlui_base.CLASS_PANEL: XMLUIPanel, 643 xmlui_base.create,
627 xmlui_base.CLASS_DIALOG: XMLUIDialog}) 644 class_map={xmlui_base.CLASS_PANEL: XMLUIPanel, xmlui_base.CLASS_DIALOG: XMLUIDialog},
645 )