Mercurial > libervia-backend
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() |