comparison libervia/tui/base.py @ 4270:0d7bb4df2343

Reformatted code base using black.
author Goffi <goffi@goffi.org>
date Wed, 19 Jun 2024 18:44:57 +0200
parents 10b6ad569157
children
comparison
equal deleted inserted replaced
4269:64a85ce8be70 4270:0d7bb4df2343
18 18
19 19
20 from libervia.backend.core.i18n import _, D_ 20 from libervia.backend.core.i18n import _, D_
21 from libervia.tui.constants import Const as C 21 from libervia.tui.constants import Const as C
22 from libervia.backend.core import log_config 22 from libervia.backend.core import log_config
23
23 log_config.libervia_configure(C.LOG_BACKEND_STANDARD, C) 24 log_config.libervia_configure(C.LOG_BACKEND_STANDARD, C)
24 from libervia.backend.core import log as logging 25 from libervia.backend.core import log as logging
26
25 log = logging.getLogger(__name__) 27 log = logging.getLogger(__name__)
26 from libervia.backend.tools import config as sat_config 28 from libervia.backend.tools import config as sat_config
27 import urwid 29 import urwid
28 from urwid.util import is_wide_char 30 from urwid.util import is_wide_char
29 from urwid_satext import sat_widgets 31 from urwid_satext import sat_widgets
41 from libervia.frontends.tools.misc import InputHistory 43 from libervia.frontends.tools.misc import InputHistory
42 from libervia.backend.tools.common import dynamic_import 44 from libervia.backend.tools.common import dynamic_import
43 from libervia.frontends.tools import jid 45 from libervia.frontends.tools import jid
44 import signal 46 import signal
45 import sys 47 import sys
48
46 ## bridge handling 49 ## bridge handling
47 # we get bridge name from conf and initialise the right class accordingly 50 # we get bridge name from conf and initialise the right class accordingly
48 main_config = sat_config.parse_main_conf() 51 main_config = sat_config.parse_main_conf()
49 bridge_name = sat_config.config_get(main_config, '', 'bridge', 'dbus') 52 bridge_name = sat_config.config_get(main_config, "", "bridge", "dbus")
50 if 'dbus' not in bridge_name: 53 if "dbus" not in bridge_name:
51 print(u"only D-Bus bridge is currently supported") 54 print("only D-Bus bridge is currently supported")
52 sys.exit(3) 55 sys.exit(3)
53 56
54 57
55 class EditBar(sat_widgets.ModalEdit): 58 class EditBar(sat_widgets.ModalEdit):
56 """ 59 """
57 The modal edit bar where you would enter messages and commands. 60 The modal edit bar where you would enter messages and commands.
58 """ 61 """
59 62
60 def __init__(self, host): 63 def __init__(self, host):
61 modes = {None: (C.MODE_NORMAL, u''), 64 modes = {
62 a_key['MODE_INSERTION']: (C.MODE_INSERTION, u'> '), 65 None: (C.MODE_NORMAL, ""),
63 a_key['MODE_COMMAND']: (C.MODE_COMMAND, u':')} #XXX: captions *MUST* be unicode 66 a_key["MODE_INSERTION"]: (C.MODE_INSERTION, "> "),
67 a_key["MODE_COMMAND"]: (C.MODE_COMMAND, ":"),
68 } # XXX: captions *MUST* be unicode
64 super(EditBar, self).__init__(modes) 69 super(EditBar, self).__init__(modes)
65 self.host = host 70 self.host = host
66 self.set_completion_method(self._text_completion) 71 self.set_completion_method(self._text_completion)
67 urwid.connect_signal(self, 'click', self.on_text_entered) 72 urwid.connect_signal(self, "click", self.on_text_entered)
68 73
69 def _text_completion(self, text, completion_data, mode): 74 def _text_completion(self, text, completion_data, mode):
70 if mode == C.MODE_INSERTION: 75 if mode == C.MODE_INSERTION:
71 if self.host.selected_widget is not None: 76 if self.host.selected_widget is not None:
72 try: 77 try:
83 if self.mode == C.MODE_INSERTION: 88 if self.mode == C.MODE_INSERTION:
84 if isinstance(self.host.selected_widget, quick_chat.QuickChat): 89 if isinstance(self.host.selected_widget, quick_chat.QuickChat):
85 chat_widget = self.host.selected_widget 90 chat_widget = self.host.selected_widget
86 self.host.message_send( 91 self.host.message_send(
87 chat_widget.target, 92 chat_widget.target,
88 {'': editBar.get_edit_text()}, # TODO: handle language 93 {"": editBar.get_edit_text()}, # TODO: handle language
89 mess_type = C.MESS_TYPE_GROUPCHAT if chat_widget.type == C.CHAT_GROUP else C.MESS_TYPE_CHAT, # TODO: put this in QuickChat 94 mess_type=(
90 errback=lambda failure: self.host.show_dialog(_("Error while sending message ({})").format(failure), type="error"), 95 C.MESS_TYPE_GROUPCHAT
91 profile_key=chat_widget.profile 96 if chat_widget.type == C.CHAT_GROUP
92 ) 97 else C.MESS_TYPE_CHAT
93 editBar.set_edit_text('') 98 ), # TODO: put this in QuickChat
99 errback=lambda failure: self.host.show_dialog(
100 _("Error while sending message ({})").format(failure),
101 type="error",
102 ),
103 profile_key=chat_widget.profile,
104 )
105 editBar.set_edit_text("")
94 elif self.mode == C.MODE_COMMAND: 106 elif self.mode == C.MODE_COMMAND:
95 self.command_handler() 107 self.command_handler()
96 108
97 def command_handler(self): 109 def command_handler(self):
98 #TODO: separate class with auto documentation (with introspection) 110 # TODO: separate class with auto documentation (with introspection)
99 # and completion method 111 # and completion method
100 tokens = self.get_edit_text().split(' ') 112 tokens = self.get_edit_text().split(" ")
101 command, args = tokens[0], tokens[1:] 113 command, args = tokens[0], tokens[1:]
102 if command == 'quit': 114 if command == "quit":
103 self.host.on_exit() 115 self.host.on_exit()
104 raise urwid.ExitMainLoop() 116 raise urwid.ExitMainLoop()
105 elif command == 'messages': 117 elif command == "messages":
106 wid = sat_widgets.GenericList(logging.memory_get()) 118 wid = sat_widgets.GenericList(logging.memory_get())
107 self.host.select_widget(wid) 119 self.host.select_widget(wid)
108 # FIXME: reactivate the command 120 # FIXME: reactivate the command
109 # elif command == 'presence': 121 # elif command == 'presence':
110 # values = [value for value in commonConst.PRESENCE.keys()] 122 # values = [value for value in commonConst.PRESENCE.keys()]
117 # elif command == 'status': 129 # elif command == 'status':
118 # if args: 130 # if args:
119 # self.host.status_bar.on_change(user_data=sat_widgets.AdvancedEdit(args[0])) 131 # self.host.status_bar.on_change(user_data=sat_widgets.AdvancedEdit(args[0]))
120 # else: 132 # else:
121 # self.host.status_bar.on_status_click() 133 # self.host.status_bar.on_status_click()
122 elif command == 'history': 134 elif command == "history":
123 widget = self.host.selected_widget 135 widget = self.host.selected_widget
124 if isinstance(widget, quick_chat.QuickChat): 136 if isinstance(widget, quick_chat.QuickChat):
125 try: 137 try:
126 limit = int(args[0]) 138 limit = int(args[0])
127 except (IndexError, ValueError): 139 except (IndexError, ValueError):
128 limit = 50 140 limit = 50
129 widget.update_history(size=limit, profile=widget.profile) 141 widget.update_history(size=limit, profile=widget.profile)
130 elif command == 'search': 142 elif command == "search":
131 widget = self.host.selected_widget 143 widget = self.host.selected_widget
132 if isinstance(widget, quick_chat.QuickChat): 144 if isinstance(widget, quick_chat.QuickChat):
133 pattern = " ".join(args) 145 pattern = " ".join(args)
134 if not pattern: 146 if not pattern:
135 self.host.notif_bar.add_message(D_("Please specify the globbing pattern to search for")) 147 self.host.notif_bar.add_message(
148 D_("Please specify the globbing pattern to search for")
149 )
136 else: 150 else:
137 widget.update_history(size=C.HISTORY_LIMIT_NONE, filters={'search': pattern}, profile=widget.profile) 151 widget.update_history(
138 elif command == 'filter': 152 size=C.HISTORY_LIMIT_NONE,
153 filters={"search": pattern},
154 profile=widget.profile,
155 )
156 elif command == "filter":
139 # FIXME: filter is now only for current widget, 157 # FIXME: filter is now only for current widget,
140 # need to be able to set it globally or per widget 158 # need to be able to set it globally or per widget
141 widget = self.host.selected_widget 159 widget = self.host.selected_widget
142 # FIXME: Q&D way, need to be more generic 160 # FIXME: Q&D way, need to be more generic
143 if isinstance(widget, quick_chat.QuickChat): 161 if isinstance(widget, quick_chat.QuickChat):
144 widget.set_filter(args) 162 widget.set_filter(args)
145 elif command in ('topic', 'suject', 'title'): 163 elif command in ("topic", "suject", "title"):
146 try: 164 try:
147 new_title = args[0].strip() 165 new_title = args[0].strip()
148 except IndexError: 166 except IndexError:
149 new_title = None 167 new_title = None
150 widget = self.host.selected_widget 168 widget = self.host.selected_widget
151 if isinstance(widget, quick_chat.QuickChat) and widget.type == C.CHAT_GROUP: 169 if isinstance(widget, quick_chat.QuickChat) and widget.type == C.CHAT_GROUP:
152 widget.on_subject_dialog(new_title) 170 widget.on_subject_dialog(new_title)
153 else: 171 else:
154 return 172 return
155 self.set_edit_text('') 173 self.set_edit_text("")
156 174
157 def _history_cb(self, text): 175 def _history_cb(self, text):
158 self.set_edit_text(text) 176 self.set_edit_text(text)
159 self.set_edit_pos(len(text)) 177 self.set_edit_pos(len(text))
160 178
161 def keypress(self, size, key): 179 def keypress(self, size, key):
162 """Callback when a key is pressed. Send "composing" states 180 """Callback when a key is pressed. Send "composing" states
163 and move the index of the temporary history stack.""" 181 and move the index of the temporary history stack."""
164 if key == a_key['MODAL_ESCAPE']: 182 if key == a_key["MODAL_ESCAPE"]:
165 # first save the text to the current mode, then change to NORMAL 183 # first save the text to the current mode, then change to NORMAL
166 self.host._update_input_history(self.get_edit_text(), mode=self.mode) 184 self.host._update_input_history(self.get_edit_text(), mode=self.mode)
167 self.host._update_input_history(mode=C.MODE_NORMAL) 185 self.host._update_input_history(mode=C.MODE_NORMAL)
168 if self._mode == C.MODE_NORMAL and key in self._modes: 186 if self._mode == C.MODE_NORMAL and key in self._modes:
169 self.host._update_input_history(mode=self._modes[key][0]) 187 self.host._update_input_history(mode=self._modes[key][0])
170 if key == a_key['HISTORY_PREV']: 188 if key == a_key["HISTORY_PREV"]:
171 self.host._update_input_history(self.get_edit_text(), -1, self._history_cb, self.mode) 189 self.host._update_input_history(
190 self.get_edit_text(), -1, self._history_cb, self.mode
191 )
172 return 192 return
173 elif key == a_key['HISTORY_NEXT']: 193 elif key == a_key["HISTORY_NEXT"]:
174 self.host._update_input_history(self.get_edit_text(), +1, self._history_cb, self.mode) 194 self.host._update_input_history(
195 self.get_edit_text(), +1, self._history_cb, self.mode
196 )
175 return 197 return
176 elif key == a_key['EDIT_ENTER']: 198 elif key == a_key["EDIT_ENTER"]:
177 self.host._update_input_history(self.get_edit_text(), mode=self.mode) 199 self.host._update_input_history(self.get_edit_text(), mode=self.mode)
178 else: 200 else:
179 if (self._mode == C.MODE_INSERTION 201 if (
202 self._mode == C.MODE_INSERTION
180 and isinstance(self.host.selected_widget, quick_chat.QuickChat) 203 and isinstance(self.host.selected_widget, quick_chat.QuickChat)
181 and key not in sat_widgets.FOCUS_KEYS 204 and key not in sat_widgets.FOCUS_KEYS
182 and key not in (a_key['HISTORY_PREV'], a_key['HISTORY_NEXT']) 205 and key not in (a_key["HISTORY_PREV"], a_key["HISTORY_NEXT"])
183 and self.host.sync): 206 and self.host.sync
184 self.host.bridge.chat_state_composing(self.host.selected_widget.target, self.host.selected_widget.profile) 207 ):
208 self.host.bridge.chat_state_composing(
209 self.host.selected_widget.target, self.host.selected_widget.profile
210 )
185 211
186 return super(EditBar, self).keypress(size, key) 212 return super(EditBar, self).keypress(size, key)
187 213
188 214
189 class LiberviaTUITopWidget(sat_widgets.FocusPile): 215 class LiberviaTUITopWidget(sat_widgets.FocusPile):
190 """Top most widget used in LiberviaTUI""" 216 """Top most widget used in LiberviaTUI"""
217
191 _focus_inversed = True 218 _focus_inversed = True
192 positions = ('menu', 'body', 'notif_bar', 'edit_bar') 219 positions = ("menu", "body", "notif_bar", "edit_bar")
193 can_hide = ('menu', 'notif_bar') 220 can_hide = ("menu", "notif_bar")
194 221
195 def __init__(self, body, menu, notif_bar, edit_bar): 222 def __init__(self, body, menu, notif_bar, edit_bar):
196 self._body = body 223 self._body = body
197 self._menu = menu 224 self._menu = menu
198 self._notif_bar = notif_bar 225 self._notif_bar = notif_bar
199 self._edit_bar = edit_bar 226 self._edit_bar = edit_bar
200 self._hidden = {'notif_bar'} 227 self._hidden = {"notif_bar"}
201 self._focus_extra = False 228 self._focus_extra = False
202 super(LiberviaTUITopWidget, self).__init__([('pack', self._menu), self._body, ('pack', self._edit_bar)]) 229 super(LiberviaTUITopWidget, self).__init__(
230 [("pack", self._menu), self._body, ("pack", self._edit_bar)]
231 )
203 for position in self.positions: 232 for position in self.positions:
204 setattr(self, 233 setattr(
205 position, 234 self,
206 property(lambda: self, self.widget_get(position=position), 235 position,
207 lambda pos, new_wid: self.widget_set(new_wid, position=pos)) 236 property(
208 ) 237 lambda: self,
209 self.focus_position = len(self.contents)-1 238 self.widget_get(position=position),
239 lambda pos, new_wid: self.widget_set(new_wid, position=pos),
240 ),
241 )
242 self.focus_position = len(self.contents) - 1
210 243
211 def get_visible_positions(self, keep=None): 244 def get_visible_positions(self, keep=None):
212 """Return positions that are not hidden in the right order 245 """Return positions that are not hidden in the right order
213 246
214 @param keep: if not None, this position will be keep in the right order, even if it's hidden 247 @param keep: if not None, this position will be keep in the right order, even if it's hidden
215 (can be useful to find its index) 248 (can be useful to find its index)
216 @return (list): list of visible positions 249 @return (list): list of visible positions
217 """ 250 """
218 return [pos for pos in self.positions if (keep and pos == keep) or pos not in self._hidden] 251 return [
252 pos
253 for pos in self.positions
254 if (keep and pos == keep) or pos not in self._hidden
255 ]
219 256
220 def keypress(self, size, key): 257 def keypress(self, size, key):
221 """Manage FOCUS keys that focus directly a main part (one of self.positions) 258 """Manage FOCUS keys that focus directly a main part (one of self.positions)
222 259
223 To avoid key conflicts, a combinaison must be made with FOCUS_EXTRA then an other key 260 To avoid key conflicts, a combinaison must be made with FOCUS_EXTRA then an other key
224 """ 261 """
225 if key == a_key['FOCUS_EXTRA']: 262 if key == a_key["FOCUS_EXTRA"]:
226 self._focus_extra = True 263 self._focus_extra = True
227 return 264 return
228 if self._focus_extra: 265 if self._focus_extra:
229 self._focus_extra = False 266 self._focus_extra = False
230 if key in ('m', '1'): 267 if key in ("m", "1"):
231 focus = 'menu' 268 focus = "menu"
232 elif key in ('b', '2'): 269 elif key in ("b", "2"):
233 focus = 'body' 270 focus = "body"
234 elif key in ('n', '3'): 271 elif key in ("n", "3"):
235 focus = 'notif_bar' 272 focus = "notif_bar"
236 elif key in ('e', '4'): 273 elif key in ("e", "4"):
237 focus = 'edit_bar' 274 focus = "edit_bar"
238 else: 275 else:
239 return super(LiberviaTUITopWidget, self).keypress(size, key) 276 return super(LiberviaTUITopWidget, self).keypress(size, key)
240 277
241 if focus in self._hidden: 278 if focus in self._hidden:
242 return 279 return
244 self.focus_position = self.get_visible_positions().index(focus) 281 self.focus_position = self.get_visible_positions().index(focus)
245 return 282 return
246 283
247 return super(LiberviaTUITopWidget, self).keypress(size, key) 284 return super(LiberviaTUITopWidget, self).keypress(size, key)
248 285
249 def widget_get(self, position): 286 def widget_get(self, position):
250 if not position in self.positions: 287 if not position in self.positions:
251 raise ValueError("Unknown position {}".format(position)) 288 raise ValueError("Unknown position {}".format(position))
252 return getattr(self, "_{}".format(position)) 289 return getattr(self, "_{}".format(position))
253 290
254 def widget_set(self, widget, position): 291 def widget_set(self, widget, position):
255 if not position in self.positions: 292 if not position in self.positions:
256 raise ValueError("Unknown position {}".format(position)) 293 raise ValueError("Unknown position {}".format(position))
257 return setattr(self, "_{}".format(position), widget) 294 return setattr(self, "_{}".format(position), widget)
258 295
259 def hide_switch(self, position): 296 def hide_switch(self, position):
264 idx = self.get_visible_positions(position).index(position) 301 idx = self.get_visible_positions(position).index(position)
265 if hide: 302 if hide:
266 del self.contents[idx] 303 del self.contents[idx]
267 self._hidden.add(position) 304 self._hidden.add(position)
268 else: 305 else:
269 self.contents.insert(idx, (widget, ('pack', None))) 306 self.contents.insert(idx, (widget, ("pack", None)))
270 self._hidden.remove(position) 307 self._hidden.remove(position)
271 308
272 def show(self, position): 309 def show(self, position):
273 if position in self._hidden: 310 if position in self._hidden:
274 self.hide_switch(position) 311 self.hide_switch(position)
281 class LiberviaTUIApp(QuickApp, InputHistory): 318 class LiberviaTUIApp(QuickApp, InputHistory):
282 MB_HANDLER = False 319 MB_HANDLER = False
283 AVATARS_HANDLER = False 320 AVATARS_HANDLER = False
284 321
285 def __init__(self): 322 def __init__(self):
286 bridge_module = dynamic_import.bridge(bridge_name, 'libervia.frontends.bridge') 323 bridge_module = dynamic_import.bridge(bridge_name, "libervia.frontends.bridge")
287 if bridge_module is None: 324 if bridge_module is None:
288 log.error(u"Can't import {} bridge".format(bridge_name)) 325 log.error("Can't import {} bridge".format(bridge_name))
289 sys.exit(3) 326 sys.exit(3)
290 else: 327 else:
291 log.debug(u"Loading {} bridge".format(bridge_name)) 328 log.debug("Loading {} bridge".format(bridge_name))
292 QuickApp.__init__(self, bridge_factory=bridge_module.bridge, xmlui=xmlui, check_options=quick_utils.check_options, connect_bridge=False) 329 QuickApp.__init__(
330 self,
331 bridge_factory=bridge_module.bridge,
332 xmlui=xmlui,
333 check_options=quick_utils.check_options,
334 connect_bridge=False,
335 )
293 ## main loop setup ## 336 ## main loop setup ##
294 event_loop = urwid.GLibEventLoop if 'dbus' in bridge_name else urwid.TwistedEventLoop 337 event_loop = (
295 self.loop = urwid.MainLoop(urwid.SolidFill(), C.PALETTE, event_loop=event_loop(), input_filter=self.input_filter, unhandled_input=self.key_handler) 338 urwid.GLibEventLoop if "dbus" in bridge_name else urwid.TwistedEventLoop
339 )
340 self.loop = urwid.MainLoop(
341 urwid.SolidFill(),
342 C.PALETTE,
343 event_loop=event_loop(),
344 input_filter=self.input_filter,
345 unhandled_input=self.key_handler,
346 )
296 347
297 @classmethod 348 @classmethod
298 def run(cls): 349 def run(cls):
299 cls().start() 350 cls().start()
300 351
301 def on_bridge_connected(self): 352 def on_bridge_connected(self):
302 353
303 ##misc setup## 354 ##misc setup##
304 self._visible_widgets = set() 355 self._visible_widgets = set()
305 self.notif_bar = sat_widgets.NotificationBar() 356 self.notif_bar = sat_widgets.NotificationBar()
306 urwid.connect_signal(self.notif_bar, 'change', self.on_notification) 357 urwid.connect_signal(self.notif_bar, "change", self.on_notification)
307 358
308 self.progress_wid = self.widgets.get_or_create_widget(Progress, None, on_new_widget=None) 359 self.progress_wid = self.widgets.get_or_create_widget(
309 urwid.connect_signal(self.notif_bar.progress, 'click', lambda x: self.select_widget(self.progress_wid)) 360 Progress, None, on_new_widget=None
361 )
362 urwid.connect_signal(
363 self.notif_bar.progress,
364 "click",
365 lambda x: self.select_widget(self.progress_wid),
366 )
310 self.__saved_overlay = None 367 self.__saved_overlay = None
311 368
312 self.x_notify = Notify() 369 self.x_notify = Notify()
313 370
314 # we already manage exit with a_key['APP_QUIT'], so we don't want C-c 371 # we already manage exit with a_key['APP_QUIT'], so we don't want C-c
315 signal.signal(signal.SIGINT, signal.SIG_IGN) 372 signal.signal(signal.SIGINT, signal.SIG_IGN)
316 sat_conf = sat_config.parse_main_conf() 373 sat_conf = sat_config.parse_main_conf()
317 self._bracketed_paste = C.bool( 374 self._bracketed_paste = C.bool(
318 sat_config.config_get(sat_conf, C.CONFIG_SECTION, 'bracketed_paste', 'false') 375 sat_config.config_get(sat_conf, C.CONFIG_SECTION, "bracketed_paste", "false")
319 ) 376 )
320 if self._bracketed_paste: 377 if self._bracketed_paste:
321 log.debug("setting bracketed paste mode as requested") 378 log.debug("setting bracketed paste mode as requested")
322 sys.stdout.write("\033[?2004h") 379 sys.stdout.write("\033[?2004h")
323 self._bracketed_mode_set = True 380 self._bracketed_mode_set = True
342 if not self.editBar.get_edit_text(): 399 if not self.editBar.get_edit_text():
343 self.mode = value 400 self.mode = value
344 401
345 def debug(self): 402 def debug(self):
346 """convenient method to reset screen and launch (i)p(u)db""" 403 """convenient method to reset screen and launch (i)p(u)db"""
347 log.info('Entered debug mode') 404 log.info("Entered debug mode")
348 try: 405 try:
349 import pudb 406 import pudb
407
350 pudb.set_trace() 408 pudb.set_trace()
351 except ImportError: 409 except ImportError:
352 import os 410 import os
353 os.system('reset') 411
412 os.system("reset")
354 try: 413 try:
355 import ipdb 414 import ipdb
415
356 ipdb.set_trace() 416 ipdb.set_trace()
357 except ImportError: 417 except ImportError:
358 import pdb 418 import pdb
419
359 pdb.set_trace() 420 pdb.set_trace()
360 421
361 def redraw(self): 422 def redraw(self):
362 """redraw the screen""" 423 """redraw the screen"""
363 try: 424 try:
371 432
372 def post_init(self): 433 def post_init(self):
373 try: 434 try:
374 config.apply_config(self) 435 config.apply_config(self)
375 except Exception as e: 436 except Exception as e:
376 log.error(u"configuration error: {}".format(e)) 437 log.error("configuration error: {}".format(e))
377 popup = self.alert(_(u"Configuration Error"), _(u"Something went wrong while reading the configuration, please check :messages")) 438 popup = self.alert(
439 _("Configuration Error"),
440 _(
441 "Something went wrong while reading the configuration, please check :messages"
442 ),
443 )
378 if self.options.profile: 444 if self.options.profile:
379 self._early_popup = popup 445 self._early_popup = popup
380 else: 446 else:
381 self.show_pop_up(popup) 447 self.show_pop_up(popup)
382 super(LiberviaTUIApp, self).post_init(self.main_widget) 448 super(LiberviaTUIApp, self).post_init(self.main_widget)
383 449
384 def keys_to_text(self, keys): 450 def keys_to_text(self, keys):
385 """Generator return normal text from urwid keys""" 451 """Generator return normal text from urwid keys"""
386 for k in keys: 452 for k in keys:
387 if k == 'tab': 453 if k == "tab":
388 yield u'\t' 454 yield "\t"
389 elif k == 'enter': 455 elif k == "enter":
390 yield u'\n' 456 yield "\n"
391 elif is_wide_char(k,0) or (len(k)==1 and ord(k) >= 32): 457 elif is_wide_char(k, 0) or (len(k) == 1 and ord(k) >= 32):
392 yield k 458 yield k
393 459
394 def input_filter(self, input_, raw): 460 def input_filter(self, input_, raw):
395 if self.__saved_overlay and input_ != a_key['OVERLAY_HIDE']: 461 if self.__saved_overlay and input_ != a_key["OVERLAY_HIDE"]:
396 return 462 return
397 463
398 ## paste detection/handling 464 ## paste detection/handling
399 if (len(input_) > 1 and # XXX: it may be needed to increase this value if buffer 465 if (
400 not isinstance(input_[0], tuple) and # or other things result in several chars at once 466 len(input_) > 1 # XXX: it may be needed to increase this value if buffer
401 not 'window resize' in input_): # (e.g. using LiberviaTUI through ssh). Need some testing 467 and not isinstance(
402 # and experience to adjust value. 468 input_[0], tuple
403 if input_[0] == 'begin paste' and not self._bracketed_paste: 469 ) # or other things result in several chars at once
404 log.info(u"Bracketed paste mode detected") 470 and not "window resize" in input_
471 ): # (e.g. using LiberviaTUI through ssh). Need some testing
472 # and experience to adjust value.
473 if input_[0] == "begin paste" and not self._bracketed_paste:
474 log.info("Bracketed paste mode detected")
405 self._bracketed_paste = True 475 self._bracketed_paste = True
406 476
407 if self._bracketed_paste: 477 if self._bracketed_paste:
408 # after this block, extra will contain non pasted keys 478 # after this block, extra will contain non pasted keys
409 # and input_ will contain pasted keys 479 # and input_ will contain pasted keys
410 try: 480 try:
411 begin_idx = input_.index('begin paste') 481 begin_idx = input_.index("begin paste")
412 except ValueError: 482 except ValueError:
413 # this is not a paste, maybe we have something buffering 483 # this is not a paste, maybe we have something buffering
414 # or bracketed mode is set in conf but not enabled in term 484 # or bracketed mode is set in conf but not enabled in term
415 extra = input_ 485 extra = input_
416 input_ = [] 486 input_ = []
417 else: 487 else:
418 try: 488 try:
419 end_idx = input_.index('end paste') 489 end_idx = input_.index("end paste")
420 except ValueError: 490 except ValueError:
421 log.warning(u"missing end paste sequence, discarding paste") 491 log.warning("missing end paste sequence, discarding paste")
422 extra = input_[:begin_idx] 492 extra = input_[:begin_idx]
423 del input_[begin_idx:] 493 del input_[begin_idx:]
424 else: 494 else:
425 extra = input_[:begin_idx] + input_[end_idx+1:] 495 extra = input_[:begin_idx] + input_[end_idx + 1 :]
426 input_ = input_[begin_idx+1:end_idx] 496 input_ = input_[begin_idx + 1 : end_idx]
427 else: 497 else:
428 extra = None 498 extra = None
429 499
430 log.debug(u"Paste detected (len {})".format(len(input_))) 500 log.debug("Paste detected (len {})".format(len(input_)))
431 try: 501 try:
432 edit_bar = self.editBar 502 edit_bar = self.editBar
433 except AttributeError: 503 except AttributeError:
434 log.warning(u"Paste treated as normal text: there is no edit bar yet") 504 log.warning("Paste treated as normal text: there is no edit bar yet")
435 if extra is None: 505 if extra is None:
436 extra = [] 506 extra = []
437 extra.extend(input_) 507 extra.extend(input_)
438 else: 508 else:
439 if self.main_widget.focus == edit_bar: 509 if self.main_widget.focus == edit_bar:
440 # XXX: if a paste is detected, we append it directly to the edit bar text 510 # XXX: if a paste is detected, we append it directly to the edit bar text
441 # so the user can check it and press [enter] if it's OK 511 # so the user can check it and press [enter] if it's OK
442 buf_paste = u''.join(self.keys_to_text(input_)) 512 buf_paste = "".join(self.keys_to_text(input_))
443 pos = edit_bar.edit_pos 513 pos = edit_bar.edit_pos
444 edit_bar.set_edit_text(u'{}{}{}'.format(edit_bar.edit_text[:pos], buf_paste, edit_bar.edit_text[pos:])) 514 edit_bar.set_edit_text(
445 edit_bar.edit_pos+=len(buf_paste) 515 "{}{}{}".format(
516 edit_bar.edit_text[:pos], buf_paste, edit_bar.edit_text[pos:]
517 )
518 )
519 edit_bar.edit_pos += len(buf_paste)
446 else: 520 else:
447 # we are not on the edit_bar, 521 # we are not on the edit_bar,
448 # so we treat pasted text as normal text 522 # so we treat pasted text as normal text
449 if extra is None: 523 if extra is None:
450 extra = [] 524 extra = []
453 return 527 return
454 input_ = extra 528 input_ = extra
455 ## end of paste detection/handling 529 ## end of paste detection/handling
456 530
457 for i in input_: 531 for i in input_:
458 if isinstance(i,tuple): 532 if isinstance(i, tuple):
459 if i[0] == 'mouse press': 533 if i[0] == "mouse press":
460 if i[1] == 4: #Mouse wheel up 534 if i[1] == 4: # Mouse wheel up
461 input_[input_.index(i)] = a_key['HISTORY_PREV'] 535 input_[input_.index(i)] = a_key["HISTORY_PREV"]
462 if i[1] == 5: #Mouse wheel down 536 if i[1] == 5: # Mouse wheel down
463 input_[input_.index(i)] = a_key['HISTORY_NEXT'] 537 input_[input_.index(i)] = a_key["HISTORY_NEXT"]
464 return input_ 538 return input_
465 539
466 def key_handler(self, input_): 540 def key_handler(self, input_):
467 if input_ == a_key['MENU_HIDE']: 541 if input_ == a_key["MENU_HIDE"]:
468 """User want to (un)hide the menu roller""" 542 """User want to (un)hide the menu roller"""
469 try: 543 try:
470 self.main_widget.hide_switch('menu') 544 self.main_widget.hide_switch("menu")
471 except AttributeError: 545 except AttributeError:
472 pass 546 pass
473 elif input_ == a_key['NOTIFICATION_NEXT']: 547 elif input_ == a_key["NOTIFICATION_NEXT"]:
474 """User wants to see next notification""" 548 """User wants to see next notification"""
475 self.notif_bar.show_next() 549 self.notif_bar.show_next()
476 elif input_ == a_key['OVERLAY_HIDE']: 550 elif input_ == a_key["OVERLAY_HIDE"]:
477 """User wants to (un)hide overlay window""" 551 """User wants to (un)hide overlay window"""
478 if isinstance(self.loop.widget,urwid.Overlay): 552 if isinstance(self.loop.widget, urwid.Overlay):
479 self.__saved_overlay = self.loop.widget 553 self.__saved_overlay = self.loop.widget
480 self.loop.widget = self.main_widget 554 self.loop.widget = self.main_widget
481 else: 555 else:
482 if self.__saved_overlay: 556 if self.__saved_overlay:
483 self.loop.widget = self.__saved_overlay 557 self.loop.widget = self.__saved_overlay
484 self.__saved_overlay = None 558 self.__saved_overlay = None
485 559
486 elif input_ == a_key['DEBUG'] and '.dev0' in self.bridge.version_get(): #Debug only for dev versions 560 elif (
561 input_ == a_key["DEBUG"] and ".dev0" in self.bridge.version_get()
562 ): # Debug only for dev versions
487 self.debug() 563 self.debug()
488 elif input_ == a_key['CONTACTS_HIDE']: #user wants to (un)hide the contact lists 564 elif input_ == a_key["CONTACTS_HIDE"]: # user wants to (un)hide the contact lists
489 try: 565 try:
490 for wid, options in self.center_part.contents: 566 for wid, options in self.center_part.contents:
491 if self.contact_lists_pile is wid: 567 if self.contact_lists_pile is wid:
492 self.center_part.contents.remove((wid, options)) 568 self.center_part.contents.remove((wid, options))
493 break 569 break
494 else: 570 else:
495 self.center_part.contents.insert(0, (self.contact_lists_pile, ('weight', 2, False))) 571 self.center_part.contents.insert(
572 0, (self.contact_lists_pile, ("weight", 2, False))
573 )
496 except AttributeError: 574 except AttributeError:
497 #The main widget is not built (probably in Profile Manager) 575 # The main widget is not built (probably in Profile Manager)
498 pass 576 pass
499 elif input_ == 'window resize': 577 elif input_ == "window resize":
500 width,height = self.loop.screen_size 578 width, height = self.loop.screen_size
501 if height<=5 and width<=35: 579 if height <= 5 and width <= 35:
502 if not 'save_main_widget' in dir(self): 580 if not "save_main_widget" in dir(self):
503 self.save_main_widget = self.loop.widget 581 self.save_main_widget = self.loop.widget
504 self.loop.widget = urwid.Filler(urwid.Text(_("Pleeeeasse, I can't even breathe !"))) 582 self.loop.widget = urwid.Filler(
583 urwid.Text(_("Pleeeeasse, I can't even breathe !"))
584 )
505 else: 585 else:
506 if 'save_main_widget' in dir(self): 586 if "save_main_widget" in dir(self):
507 self.loop.widget = self.save_main_widget 587 self.loop.widget = self.save_main_widget
508 del self.save_main_widget 588 del self.save_main_widget
509 try: 589 try:
510 return self.menu_roller.check_shortcuts(input_) 590 return self.menu_roller.check_shortcuts(input_)
511 except AttributeError: 591 except AttributeError:
516 @param menu: sat_widgets.Menu instance 596 @param menu: sat_widgets.Menu instance
517 @param type_filter: menu type like is sat.core.sat_main.import_menu 597 @param type_filter: menu type like is sat.core.sat_main.import_menu
518 @param menu_data: data to send with these menus 598 @param menu_data: data to send with these menus
519 599
520 """ 600 """
601
521 def add_menu_cb(callback_id): 602 def add_menu_cb(callback_id):
522 self.action_launch(callback_id, menu_data, profile=self.current_profile) 603 self.action_launch(callback_id, menu_data, profile=self.current_profile)
523 for id_, type_, path, path_i18n, extra in self.bridge.menus_get("", C.NO_SECURITY_LIMIT ): # TODO: manage extra 604
605 for id_, type_, path, path_i18n, extra in self.bridge.menus_get(
606 "", C.NO_SECURITY_LIMIT
607 ): # TODO: manage extra
524 if type_ != type_filter: 608 if type_ != type_filter:
525 continue 609 continue
526 if len(path) != 2: 610 if len(path) != 2:
527 raise NotImplementedError("Menu with a path != 2 are not implemented yet") 611 raise NotImplementedError("Menu with a path != 2 are not implemented yet")
528 menu.add_menu(path_i18n[0], path_i18n[1], lambda dummy,id_=id_: add_menu_cb(id_)) 612 menu.add_menu(
529 613 path_i18n[0], path_i18n[1], lambda dummy, id_=id_: add_menu_cb(id_)
614 )
530 615
531 def _build_menu_roller(self): 616 def _build_menu_roller(self):
532 menu = sat_widgets.Menu(self.loop) 617 menu = sat_widgets.Menu(self.loop)
533 general = _("General") 618 general = _("General")
534 menu.add_menu(general, _("Connect"), self.on_connect_request) 619 menu.add_menu(general, _("Connect"), self.on_connect_request)
535 menu.add_menu(general, _("Disconnect"), self.on_disconnect_request) 620 menu.add_menu(general, _("Disconnect"), self.on_disconnect_request)
536 menu.add_menu(general, _("Parameters"), self.on_param) 621 menu.add_menu(general, _("Parameters"), self.on_param)
537 menu.add_menu(general, _("About"), self.on_about_request) 622 menu.add_menu(general, _("About"), self.on_about_request)
538 menu.add_menu(general, _("Exit"), self.on_exit_request, a_key['APP_QUIT']) 623 menu.add_menu(general, _("Exit"), self.on_exit_request, a_key["APP_QUIT"])
539 menu.add_menu(_("Contacts")) # add empty menu to save the place in the menu order 624 menu.add_menu(_("Contacts")) # add empty menu to save the place in the menu order
540 groups = _("Groups") 625 groups = _("Groups")
541 menu.add_menu(groups) 626 menu.add_menu(groups)
542 menu.add_menu(groups, _("Join room"), self.on_join_room_request, a_key['ROOM_JOIN']) 627 menu.add_menu(
543 #additionals menus 628 groups, _("Join room"), self.on_join_room_request, a_key["ROOM_JOIN"]
544 #FIXME: do this in a more generic way (in quickapp) 629 )
630 # additionals menus
631 # FIXME: do this in a more generic way (in quickapp)
545 self.add_menus(menu, C.MENU_GLOBAL) 632 self.add_menus(menu, C.MENU_GLOBAL)
546 633
547 menu_roller = sat_widgets.MenuRoller([(_('Main menu'), menu, C.MENU_ID_MAIN)]) 634 menu_roller = sat_widgets.MenuRoller([(_("Main menu"), menu, C.MENU_ID_MAIN)])
548 return menu_roller 635 return menu_roller
549 636
550 def _build_main_widget(self): 637 def _build_main_widget(self):
551 self.contact_lists_pile = urwid.Pile([]) 638 self.contact_lists_pile = urwid.Pile([])
552 #self.center_part = urwid.Columns([('weight',2,self.contact_lists[profile]),('weight',8,Chat('',self))]) 639 # self.center_part = urwid.Columns([('weight',2,self.contact_lists[profile]),('weight',8,Chat('',self))])
553 self.center_part = urwid.Columns([('weight', 2, self.contact_lists_pile), ('weight', 8, urwid.Filler(urwid.Text('')))]) 640 self.center_part = urwid.Columns(
641 [
642 ("weight", 2, self.contact_lists_pile),
643 ("weight", 8, urwid.Filler(urwid.Text(""))),
644 ]
645 )
554 646
555 self.editBar = EditBar(self) 647 self.editBar = EditBar(self)
556 self.menu_roller = self._build_menu_roller() 648 self.menu_roller = self._build_menu_roller()
557 self.main_widget = LiberviaTUITopWidget(self.center_part, self.menu_roller, self.notif_bar, self.editBar) 649 self.main_widget = LiberviaTUITopWidget(
650 self.center_part, self.menu_roller, self.notif_bar, self.editBar
651 )
558 return self.main_widget 652 return self.main_widget
559 653
560 def plugging_profiles(self): 654 def plugging_profiles(self):
561 self.loop.widget = self._build_main_widget() 655 self.loop.widget = self._build_main_widget()
562 self.redraw() 656 self.redraw()
568 else: 662 else:
569 del self._early_popup 663 del self._early_popup
570 664
571 def profile_plugged(self, profile): 665 def profile_plugged(self, profile):
572 QuickApp.profile_plugged(self, profile) 666 QuickApp.profile_plugged(self, profile)
573 contact_list = self.widgets.get_or_create_widget(ContactList, None, on_new_widget=None, on_click=self.contact_selected, on_change=lambda w: self.redraw(), profile=profile) 667 contact_list = self.widgets.get_or_create_widget(
574 self.contact_lists_pile.contents.append((contact_list, ('weight', 1))) 668 ContactList,
669 None,
670 on_new_widget=None,
671 on_click=self.contact_selected,
672 on_change=lambda w: self.redraw(),
673 profile=profile,
674 )
675 self.contact_lists_pile.contents.append((contact_list, ("weight", 1)))
575 return contact_list 676 return contact_list
576 677
577 def is_hidden(self): 678 def is_hidden(self):
578 """Tells if the frontend window is hidden. 679 """Tells if the frontend window is hidden.
579 680
588 @param title(unicode): title of the dialog 689 @param title(unicode): title of the dialog
589 @param message(unicode): body of the dialog 690 @param message(unicode): body of the dialog
590 @return (urwid_satext.Alert): the created Alert instance 691 @return (urwid_satext.Alert): the created Alert instance
591 """ 692 """
592 popup = sat_widgets.Alert(title, message) 693 popup = sat_widgets.Alert(title, message)
593 popup.set_callback('ok', lambda dummy: self.remove_pop_up(popup)) 694 popup.set_callback("ok", lambda dummy: self.remove_pop_up(popup))
594 self.show_pop_up(popup, width=75, height=20) 695 self.show_pop_up(popup, width=75, height=20)
595 return popup 696 return popup
596 697
597 def remove_pop_up(self, widget=None): 698 def remove_pop_up(self, widget=None):
598 """Remove current pop-up, and if there is other in queue, show it 699 """Remove current pop-up, and if there is other in queue, show it
607 current_popup = self.loop.widget.top_w 708 current_popup = self.loop.widget.top_w
608 if not current_popup == widget: 709 if not current_popup == widget:
609 try: 710 try:
610 self.notif_bar.remove_pop_up(widget) 711 self.notif_bar.remove_pop_up(widget)
611 except ValueError: 712 except ValueError:
612 log.warning(u"Trying to remove an unknown widget {}".format(widget)) 713 log.warning(
714 "Trying to remove an unknown widget {}".format(widget)
715 )
613 return 716 return
614 self.loop.widget = self.main_widget 717 self.loop.widget = self.main_widget
615 next_popup = self.notif_bar.get_next_popup() 718 next_popup = self.notif_bar.get_next_popup()
616 if next_popup: 719 if next_popup:
617 #we still have popup to show, we display it 720 # we still have popup to show, we display it
618 self.show_pop_up(next_popup) 721 self.show_pop_up(next_popup)
619 else: 722 else:
620 self.redraw() 723 self.redraw()
621 724
622 def show_pop_up(self, pop_up_widget, width=None, height=None, align='center', 725 def show_pop_up(
623 valign='middle'): 726 self, pop_up_widget, width=None, height=None, align="center", valign="middle"
727 ):
624 """Show a pop-up window if possible, else put it in queue 728 """Show a pop-up window if possible, else put it in queue
625 729
626 @param pop_up_widget: pop up to show 730 @param pop_up_widget: pop up to show
627 @param width(int, None): width of the popup 731 @param width(int, None): width of the popup
628 None to use default 732 None to use default
634 width = 75 if isinstance(pop_up_widget, xmlui.LiberviaTUINoteDialog) else 135 738 width = 75 if isinstance(pop_up_widget, xmlui.LiberviaTUINoteDialog) else 135
635 if height == None: 739 if height == None:
636 height = 20 if isinstance(pop_up_widget, xmlui.LiberviaTUINoteDialog) else 40 740 height = 20 if isinstance(pop_up_widget, xmlui.LiberviaTUINoteDialog) else 40
637 if not isinstance(self.loop.widget, urwid.Overlay): 741 if not isinstance(self.loop.widget, urwid.Overlay):
638 display_widget = urwid.Overlay( 742 display_widget = urwid.Overlay(
639 pop_up_widget, self.main_widget, align, width, valign, height) 743 pop_up_widget, self.main_widget, align, width, valign, height
744 )
640 self.loop.widget = display_widget 745 self.loop.widget = display_widget
641 self.redraw() 746 self.redraw()
642 else: 747 else:
643 self.notif_bar.add_pop_up(pop_up_widget) 748 self.notif_bar.add_pop_up(pop_up_widget)
644 749
645 def bar_notify(self, message): 750 def bar_notify(self, message):
646 """"Notify message to user via notification bar""" 751 """ "Notify message to user via notification bar"""
647 self.notif_bar.add_message(message) 752 self.notif_bar.add_message(message)
648 self.redraw() 753 self.redraw()
649 754
650 def notify(self, type_, entity=None, message=None, subject=None, callback=None, cb_args=None, widget=None, profile=C.PROF_KEY_NONE): 755 def notify(
756 self,
757 type_,
758 entity=None,
759 message=None,
760 subject=None,
761 callback=None,
762 cb_args=None,
763 widget=None,
764 profile=C.PROF_KEY_NONE,
765 ):
651 if widget is None or widget is not None and widget != self.selected_widget: 766 if widget is None or widget is not None and widget != self.selected_widget:
652 # we ignore notification if the widget is selected but we can 767 # we ignore notification if the widget is selected but we can
653 # still do a desktop notification is the X window has not the focus 768 # still do a desktop notification is the X window has not the focus
654 super(LiberviaTUIApp, self).notify(type_, entity, message, subject, callback, cb_args, widget, profile) 769 super(LiberviaTUIApp, self).notify(
770 type_, entity, message, subject, callback, cb_args, widget, profile
771 )
655 # we don't want notifications without message on desktop 772 # we don't want notifications without message on desktop
656 if message is not None and not self.x_notify.has_focus(): 773 if message is not None and not self.x_notify.has_focus():
657 if message is None: 774 if message is None:
658 message = _("{app}: a new event has just happened{entity}").format( 775 message = _("{app}: a new event has just happened{entity}").format(
659 app=C.APP_NAME, 776 app=C.APP_NAME, entity=" ({})".format(entity) if entity else ""
660 entity=u' ({})'.format(entity) if entity else '') 777 )
661 self.x_notify.send_notification(message) 778 self.x_notify.send_notification(message)
662
663 779
664 def new_widget(self, widget, user_action=False): 780 def new_widget(self, widget, user_action=False):
665 """Method called when a new widget is created 781 """Method called when a new widget is created
666 782
667 if suitable, the widget will be displayed 783 if suitable, the widget will be displayed
678 """Display a widget if possible, 794 """Display a widget if possible,
679 795
680 else add it in the notification bar queue 796 else add it in the notification bar queue
681 @param widget: BoxWidget 797 @param widget: BoxWidget
682 """ 798 """
683 assert len(self.center_part.widget_list)<=2 799 assert len(self.center_part.widget_list) <= 2
684 wid_idx = len(self.center_part.widget_list)-1 800 wid_idx = len(self.center_part.widget_list) - 1
685 self.center_part.widget_list[wid_idx] = widget 801 self.center_part.widget_list[wid_idx] = widget
686 try: 802 try:
687 self.menu_roller.remove_menu(C.MENU_ID_WIDGET) 803 self.menu_roller.remove_menu(C.MENU_ID_WIDGET)
688 except KeyError: 804 except KeyError:
689 log.debug("No menu to delete") 805 log.debug("No menu to delete")
692 on_selected = self.selected_widget.on_selected 808 on_selected = self.selected_widget.on_selected
693 except AttributeError: 809 except AttributeError:
694 pass 810 pass
695 else: 811 else:
696 on_selected() 812 on_selected()
697 self._visible_widgets = set([widget]) # XXX: we can only have one widget visible at the time for now 813 self._visible_widgets = set(
814 [widget]
815 ) # XXX: we can only have one widget visible at the time for now
698 self.contact_lists.select(None) 816 self.contact_lists.select(None)
699 817
700 for wid in self.visible_widgets: # FIXME: check if widgets.get_widgets is not more appropriate 818 for (
819 wid
820 ) in (
821 self.visible_widgets
822 ): # FIXME: check if widgets.get_widgets is not more appropriate
701 if isinstance(wid, Chat): 823 if isinstance(wid, Chat):
702 contact_list = self.contact_lists[wid.profile] 824 contact_list = self.contact_lists[wid.profile]
703 contact_list.select(wid.target) 825 contact_list.select(wid.target)
704 826
705 self.redraw() 827 self.redraw()
706 828
707 def remove_window(self): 829 def remove_window(self):
708 """Remove window showed on the right column""" 830 """Remove window showed on the right column"""
709 #TODO: better Window management than this hack 831 # TODO: better Window management than this hack
710 assert len(self.center_part.widget_list) <= 2 832 assert len(self.center_part.widget_list) <= 2
711 wid_idx = len(self.center_part.widget_list)-1 833 wid_idx = len(self.center_part.widget_list) - 1
712 self.center_part.widget_list[wid_idx] = urwid.Filler(urwid.Text('')) 834 self.center_part.widget_list[wid_idx] = urwid.Filler(urwid.Text(""))
713 self.center_part.focus_position = 0 835 self.center_part.focus_position = 0
714 self.redraw() 836 self.redraw()
715 837
716 def add_progress(self, pid, message, profile): 838 def add_progress(self, pid, message, profile):
717 """Follow a SàT progression 839 """Follow a SàT progression
727 849
728 def contact_selected(self, contact_list, entity): 850 def contact_selected(self, contact_list, entity):
729 self.clear_notifs(entity, profile=contact_list.profile) 851 self.clear_notifs(entity, profile=contact_list.profile)
730 if entity.resource: 852 if entity.resource:
731 # we have clicked on a private MUC conversation 853 # we have clicked on a private MUC conversation
732 chat_widget = self.widgets.get_or_create_widget(Chat, entity, on_new_widget=None, force_hash = Chat.get_private_hash(contact_list.profile, entity), profile=contact_list.profile) 854 chat_widget = self.widgets.get_or_create_widget(
733 else: 855 Chat,
734 chat_widget = self.widgets.get_or_create_widget(Chat, entity, on_new_widget=None, profile=contact_list.profile) 856 entity,
857 on_new_widget=None,
858 force_hash=Chat.get_private_hash(contact_list.profile, entity),
859 profile=contact_list.profile,
860 )
861 else:
862 chat_widget = self.widgets.get_or_create_widget(
863 Chat, entity, on_new_widget=None, profile=contact_list.profile
864 )
735 self.select_widget(chat_widget) 865 self.select_widget(chat_widget)
736 self.menu_roller.add_menu(_('Chat menu'), chat_widget.get_menu(), C.MENU_ID_WIDGET) 866 self.menu_roller.add_menu(
867 _("Chat menu"), chat_widget.get_menu(), C.MENU_ID_WIDGET
868 )
737 869
738 def _dialog_ok_cb(self, widget, data): 870 def _dialog_ok_cb(self, widget, data):
739 popup, answer_cb, answer_data = data 871 popup, answer_cb, answer_data = data
740 self.remove_pop_up(popup) 872 self.remove_pop_up(popup)
741 if answer_cb is not None: 873 if answer_cb is not None:
745 popup, answer_cb, answer_data = data 877 popup, answer_cb, answer_data = data
746 self.remove_pop_up(popup) 878 self.remove_pop_up(popup)
747 if answer_cb is not None: 879 if answer_cb is not None:
748 answer_cb(False, answer_data) 880 answer_cb(False, answer_data)
749 881
750 def show_dialog(self, message, title="", type="info", answer_cb = None, answer_data = None): 882 def show_dialog(
751 if type == 'info': 883 self, message, title="", type="info", answer_cb=None, answer_data=None
884 ):
885 if type == "info":
752 popup = sat_widgets.Alert(title, message, ok_cb=answer_cb) 886 popup = sat_widgets.Alert(title, message, ok_cb=answer_cb)
753 if answer_cb is None: 887 if answer_cb is None:
754 popup.set_callback('ok', lambda dummy: self.remove_pop_up(popup)) 888 popup.set_callback("ok", lambda dummy: self.remove_pop_up(popup))
755 elif type == 'error': 889 elif type == "error":
756 popup = sat_widgets.Alert(title, message, ok_cb=answer_cb) 890 popup = sat_widgets.Alert(title, message, ok_cb=answer_cb)
757 if answer_cb is None: 891 if answer_cb is None:
758 popup.set_callback('ok', lambda dummy: self.remove_pop_up(popup)) 892 popup.set_callback("ok", lambda dummy: self.remove_pop_up(popup))
759 elif type == 'yes/no': 893 elif type == "yes/no":
760 popup = sat_widgets.ConfirmDialog(message) 894 popup = sat_widgets.ConfirmDialog(message)
761 popup.set_callback('yes', self._dialog_ok_cb, (popup, answer_cb, answer_data)) 895 popup.set_callback("yes", self._dialog_ok_cb, (popup, answer_cb, answer_data))
762 popup.set_callback('no', self._dialog_cancel_cb, (popup, answer_cb, answer_data)) 896 popup.set_callback(
897 "no", self._dialog_cancel_cb, (popup, answer_cb, answer_data)
898 )
763 else: 899 else:
764 popup = sat_widgets.Alert(title, message, ok_cb=answer_cb) 900 popup = sat_widgets.Alert(title, message, ok_cb=answer_cb)
765 if answer_cb is None: 901 if answer_cb is None:
766 popup.set_callback('ok', lambda dummy: self.remove_pop_up(popup)) 902 popup.set_callback("ok", lambda dummy: self.remove_pop_up(popup))
767 log.error(u'unmanaged dialog type: {}'.format(type)) 903 log.error("unmanaged dialog type: {}".format(type))
768 self.show_pop_up(popup) 904 self.show_pop_up(popup)
769 905
770 def dialog_failure(self, failure): 906 def dialog_failure(self, failure):
771 """Show a failure that has been returned by an asynchronous bridge method. 907 """Show a failure that has been returned by an asynchronous bridge method.
772 908
775 self.alert(failure.classname, failure.message) 911 self.alert(failure.classname, failure.message)
776 912
777 def on_notification(self, notif_bar): 913 def on_notification(self, notif_bar):
778 """Called when a new notification has been received""" 914 """Called when a new notification has been received"""
779 if not isinstance(self.main_widget, LiberviaTUITopWidget): 915 if not isinstance(self.main_widget, LiberviaTUITopWidget):
780 #if we are not in the main configuration, we ignore the notifications bar 916 # if we are not in the main configuration, we ignore the notifications bar
781 return 917 return
782 if self.notif_bar.can_hide(): 918 if self.notif_bar.can_hide():
783 #No notification left, we can hide the bar 919 # No notification left, we can hide the bar
784 self.main_widget.hide('notif_bar') 920 self.main_widget.hide("notif_bar")
785 else: 921 else:
786 self.main_widget.show('notif_bar') 922 self.main_widget.show("notif_bar")
787 self.redraw() # FIXME: invalidate cache in a more efficient way 923 self.redraw() # FIXME: invalidate cache in a more efficient way
788 924
789 def _action_manager_unknown_error(self): 925 def _action_manager_unknown_error(self):
790 self.alert(_("Error"), _(u"Unmanaged action")) 926 self.alert(_("Error"), _("Unmanaged action"))
791 927
792 def room_joined_handler(self, room_jid_s, room_nicks, user_nick, subject, profile): 928 def room_joined_handler(self, room_jid_s, room_nicks, user_nick, subject, profile):
793 super(LiberviaTUIApp, self).room_joined_handler(room_jid_s, room_nicks, user_nick, subject, profile) 929 super(LiberviaTUIApp, self).room_joined_handler(
930 room_jid_s, room_nicks, user_nick, subject, profile
931 )
794 # if self.selected_widget is None: 932 # if self.selected_widget is None:
795 # for contact_list in self.widgets.get_widgets(ContactList): 933 # for contact_list in self.widgets.get_widgets(ContactList):
796 # if profile in contact_list.profiles: 934 # if profile in contact_list.profiles:
797 # contact_list.set_focus(jid.JID(room_jid_s), True) 935 # contact_list.set_focus(jid.JID(room_jid_s), True)
798 936
799 def progress_started_handler(self, pid, metadata, profile): 937 def progress_started_handler(self, pid, metadata, profile):
800 super(LiberviaTUIApp, self).progress_started_handler(pid, metadata, profile) 938 super(LiberviaTUIApp, self).progress_started_handler(pid, metadata, profile)
801 self.add_progress(pid, metadata.get('name', _(u'unkown')), profile) 939 self.add_progress(pid, metadata.get("name", _("unkown")), profile)
802 940
803 def progress_finished_handler(self, pid, metadata, profile): 941 def progress_finished_handler(self, pid, metadata, profile):
804 log.info(u"Progress {} finished".format(pid)) 942 log.info("Progress {} finished".format(pid))
805 super(LiberviaTUIApp, self).progress_finished_handler(pid, metadata, profile) 943 super(LiberviaTUIApp, self).progress_finished_handler(pid, metadata, profile)
806 944
807 def progress_error_handler(self, pid, err_msg, profile): 945 def progress_error_handler(self, pid, err_msg, profile):
808 log.warning(u"Progress {pid} error: {err_msg}".format(pid=pid, err_msg=err_msg)) 946 log.warning("Progress {pid} error: {err_msg}".format(pid=pid, err_msg=err_msg))
809 super(LiberviaTUIApp, self).progress_error_handler(pid, err_msg, profile) 947 super(LiberviaTUIApp, self).progress_error_handler(pid, err_msg, profile)
810
811 948
812 ##DIALOGS CALLBACKS## 949 ##DIALOGS CALLBACKS##
813 def on_join_room(self, button, edit): 950 def on_join_room(self, button, edit):
814 self.remove_pop_up() 951 self.remove_pop_up()
815 room_jid = jid.JID(edit.get_edit_text()) 952 room_jid = jid.JID(edit.get_edit_text())
816 self.bridge.muc_join(room_jid, self.profiles[self.current_profile].whoami.node, {}, self.current_profile, callback=lambda dummy: None, errback=self.dialog_failure) 953 self.bridge.muc_join(
817 954 room_jid,
818 #MENU EVENTS# 955 self.profiles[self.current_profile].whoami.node,
956 {},
957 self.current_profile,
958 callback=lambda dummy: None,
959 errback=self.dialog_failure,
960 )
961
962 # MENU EVENTS#
819 def on_connect_request(self, menu): 963 def on_connect_request(self, menu):
820 QuickApp.connect(self, self.current_profile) 964 QuickApp.connect(self, self.current_profile)
821 965
822 def on_disconnect_request(self, menu): 966 def on_disconnect_request(self, menu):
823 self.disconnect(self.current_profile) 967 self.disconnect(self.current_profile)
827 ui = xmlui.create(self, xml_data=params, profile=self.current_profile) 971 ui = xmlui.create(self, xml_data=params, profile=self.current_profile)
828 ui.show() 972 ui.show()
829 973
830 def failure(error): 974 def failure(error):
831 self.alert(_("Error"), _("Can't get parameters (%s)") % error) 975 self.alert(_("Error"), _("Can't get parameters (%s)") % error)
832 self.bridge.param_ui_get(app=C.APP_NAME, profile_key=self.current_profile, callback=success, errback=failure) 976
977 self.bridge.param_ui_get(
978 app=C.APP_NAME,
979 profile_key=self.current_profile,
980 callback=success,
981 errback=failure,
982 )
833 983
834 def on_exit_request(self, menu): 984 def on_exit_request(self, menu):
835 QuickApp.on_exit(self) 985 QuickApp.on_exit(self)
836 try: 986 try:
837 if self._bracketed_mode_set: # we don't unset if bracketed paste mode was detected automatically (i.e. not in conf) 987 if (
988 self._bracketed_mode_set
989 ): # we don't unset if bracketed paste mode was detected automatically (i.e. not in conf)
838 log.debug("unsetting bracketed paste mode") 990 log.debug("unsetting bracketed paste mode")
839 sys.stdout.write("\033[?2004l") 991 sys.stdout.write("\033[?2004l")
840 except AttributeError: 992 except AttributeError:
841 pass 993 pass
842 raise urwid.ExitMainLoop() 994 raise urwid.ExitMainLoop()
843 995
844 def on_join_room_request(self, menu): 996 def on_join_room_request(self, menu):
845 """User wants to join a MUC room""" 997 """User wants to join a MUC room"""
846 pop_up_widget = sat_widgets.InputDialog(_("Entering a MUC room"), _("Please enter MUC's JID"), default_txt=self.bridge.muc_get_default_service(), ok_cb=self.on_join_room) 998 pop_up_widget = sat_widgets.InputDialog(
847 pop_up_widget.set_callback('cancel', lambda dummy: self.remove_pop_up(pop_up_widget)) 999 _("Entering a MUC room"),
1000 _("Please enter MUC's JID"),
1001 default_txt=self.bridge.muc_get_default_service(),
1002 ok_cb=self.on_join_room,
1003 )
1004 pop_up_widget.set_callback(
1005 "cancel", lambda dummy: self.remove_pop_up(pop_up_widget)
1006 )
848 self.show_pop_up(pop_up_widget) 1007 self.show_pop_up(pop_up_widget)
849 1008
850 def on_about_request(self, menu): 1009 def on_about_request(self, menu):
851 self.alert(_("About"), C.APP_NAME + " v" + self.bridge.version_get()) 1010 self.alert(_("About"), C.APP_NAME + " v" + self.bridge.version_get())
852 1011
853 #MISC CALLBACKS# 1012 # MISC CALLBACKS#
854 1013
855 def set_presence_status(self, show='', status=None, profile=C.PROF_KEY_NONE): 1014 def set_presence_status(self, show="", status=None, profile=C.PROF_KEY_NONE):
856 contact_list_wid = self.widgets.get_widget(ContactList, profiles=profile) 1015 contact_list_wid = self.widgets.get_widget(ContactList, profiles=profile)
857 if contact_list_wid is not None: 1016 if contact_list_wid is not None:
858 contact_list_wid.status_bar.set_presence_status(show, status) 1017 contact_list_wid.status_bar.set_presence_status(show, status)
859 else: 1018 else:
860 log.warning(u"No ContactList widget found for profile {}".format(profile)) 1019 log.warning("No ContactList widget found for profile {}".format(profile))
861 1020
862 if __name__ == '__main__': 1021
1022 if __name__ == "__main__":
863 LiberviaTUIApp().start() 1023 LiberviaTUIApp().start()