# HG changeset patch # User Goffi # Date 1484511689 -3600 # Node ID 7631325e11f4c165dd98b98670fc9d29808e94c7 # Parent 953ddf817b8aab9ad93e379b72af40ee4ed66e97 chat: added completion of header's input, any entity in cache containing the entered text is shown diff -r 953ddf817b8a -r 7631325e11f4 src/cagou/plugins/plugin_wid_chat.py --- a/src/cagou/plugins/plugin_wid_chat.py Sun Jan 15 21:21:25 2017 +0100 +++ b/src/cagou/plugins/plugin_wid_chat.py Sun Jan 15 21:21:29 2017 +0100 @@ -32,6 +32,8 @@ from sat_frontends.tools import jid from cagou.core import cagou_widget from cagou.core.image import Image +from cagou.core.common import JidWidget +from kivy.uix.dropdown import DropDown from cagou import G @@ -131,6 +133,11 @@ self.host.addListener('progressFinished', self.onProgressFinished, profiles) self._waiting_pids = {} # waiting progress ids self.postInit() + # completion attribtues + self._hi_comp_data = None + self._hi_comp_last = None + self._hi_comp_dropdown = DropDown() + self._hi_comp_allowed = True @classmethod def factory(cls, plugin_info, target, profiles): @@ -141,6 +148,99 @@ target = G.host.profiles[profiles[0]].whoami return G.host.widgets.getOrCreateWidget(cls, target, on_new_widget=None, on_existing_widget=C.WIDGET_RECREATE, profiles=profiles) + ## header ## + + def changeWidget(self, jid_): + """change current widget for a new one with given jid + + @param jid_(jid.JID): jid of the widget to create + """ + plugin_info = G.host.getPluginInfo(main=Chat) + factory = plugin_info['factory'] + G.host.switchWidget(self, factory(plugin_info, jid_, profiles=[self.profile])) + self.header_input.text = '' + + def onHeaderInput(self): + text = self.header_input.text.strip() + try: + if text.count(u'@') != 1 or text.count(u' '): + raise ValueError + jid_ = jid.JID(text) + except ValueError: + log.info(u"entered text is not a jid") + return + + def discoCb(disco): + # TODO: check if plugin XEP-0045 is activated + if "conference" in [i[0] for i in disco[1]]: + G.host.bridge.mucJoin(unicode(jid_), "", "", self.profile, callback=self._mucJoinCb, errback=self._mucJoinEb) + else: + self.changeWidget(jid_) + + def discoEb(failure): + log.warning(u"Disco failure, ignore this text: {}".format(failure)) + + G.host.bridge.discoInfos(jid_.domain, self.profile, callback=discoCb, errback=discoEb) + + def onHeaderInputCompleted(self, input_wid, completed_text): + self._hi_comp_allowed = False + input_wid.text = completed_text + self._hi_comp_allowed = True + self._hi_comp_dropdown.dismiss() + self.onHeaderInput() + + def onHeaderInputComplete(self, wid, text): + if not self._hi_comp_allowed: + return + text = text.lstrip() + if not text: + self._hi_comp_data = None + self._hi_comp_last = None + return + + profile = list(self.profiles)[0] + + if self._hi_comp_data is None: + # first completion, we build the initial list + comp_data = self._hi_comp_data = [] + self._hi_comp_last = '' + for jid_, jid_data in G.host.contact_lists[profile].all_iter: + comp_data.append((jid_, jid_data)) + comp_data.sort(key=lambda datum: datum[0]) + else: + comp_data = self._hi_comp_data + + # XXX: dropdown is rebuilt each time backspace is pressed or if the text is changed, + # it works OK, but some optimisation may be done here + dropdown = self._hi_comp_dropdown + + if not text.startswith(self._hi_comp_last) or not self._hi_comp_last: + # text has changed or backspace has been pressed, we restart + dropdown.clear_widgets() + + for jid_, jid_data in comp_data: + nick = jid_data.get(u'nick', u'') + if text in jid_.bare or text in nick.lower(): + btn = JidWidget( + jid = jid_.bare, + profile = profile, + size_hint = (0.5, None), + nick = nick, + on_release=lambda dummy, txt=jid_.bare: self.onHeaderInputCompleted(wid, txt) + ) + dropdown.add_widget(btn) + else: + # more chars, we continue completion by removing unwanted widgets + to_remove = [] + for c in dropdown.children[0].children: + if text not in c.jid and text not in (c.nick or ''): + to_remove.append(c) + for c in to_remove: + dropdown.remove_widget(c) + + dropdown.open(wid) + self._hi_comp_last = text + def messageDataConverter(self, idx, mess_id): return {"mess_data": self.messages[mess_id]} @@ -238,38 +338,6 @@ def _mucJoinEb(self, failure): log.warning(u"Can't join room: {}".format(failure)) - def changeWidget(self, jid_): - """change current widget for a new one with given jid - - @param jid_(jid.JID): jid of the widget to create - """ - plugin_info = G.host.getPluginInfo(main=Chat) - factory = plugin_info['factory'] - G.host.switchWidget(self, factory(plugin_info, jid_, profiles=[self.profile])) - self.header_input.text = '' - - def onHeaderInput(self): - text = self.header_input.text.strip() - try: - if text.count(u'@') != 1 or text.count(u' '): - raise ValueError - jid_ = jid.JID(text) - except ValueError: - log.info(u"entered text is not a jid") - return - - def discoCb(disco): - # TODO: check if plugin XEP-0045 is activated - if "conference" in [i[0] for i in disco[1]]: - G.host.bridge.mucJoin(unicode(jid_), "", "", self.profile, callback=self._mucJoinCb, errback=self._mucJoinEb) - else: - self.changeWidget(jid_) - - def discoEb(failure): - log.warning(u"Disco failure, ignore this text: {}".format(failure)) - - G.host.bridge.discoInfos(jid_.domain, self.profile, callback=discoCb, errback=discoEb) - def _onDelete(self): self.host.removeListener('progressFinished', self.onProgressFinished) self.host.removeListener('progressError', self.onProgressError)