Mercurial > libervia-backend
diff frontends/src/quick_frontend/quick_chat.py @ 1367:f71a0fc26886
merged branch frontends_multi_profiles
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 18 Mar 2015 10:52:28 +0100 |
parents | ba87b940f07a |
children | 017270e6eea4 |
line wrap: on
line diff
--- a/frontends/src/quick_frontend/quick_chat.py Thu Feb 05 11:59:26 2015 +0100 +++ b/frontends/src/quick_frontend/quick_chat.py Wed Mar 18 10:52:28 2015 +0100 @@ -20,41 +20,92 @@ from sat.core.i18n import _ from sat.core.log import getLogger log = getLogger(__name__) -from sat_frontends.tools.jid import JID -from sat_frontends.quick_frontend.quick_utils import unescapePrivate +from sat_frontends.tools import jid +from sat_frontends.quick_frontend import quick_widgets from sat_frontends.quick_frontend.constants import Const as C -class QuickChat(object): +try: + # FIXME: to be removed when an acceptable solution is here + unicode('') # XXX: unicode doesn't exist in pyjamas +except (TypeError, AttributeError): # Error raised is not the same depending on pyjsbuild options + unicode = lambda x: str(x) + + +class QuickChat(quick_widgets.QuickWidget): - def __init__(self, target, host, type_='one2one'): - self.target = target - self.host = host + def __init__(self, host, target, type_=C.CHAT_ONE2ONE, profiles=None): + """ + @param type_: can be C.CHAT_ONE2ONE for single conversation or C.CHAT_GROUP for chat à la IRC + """ + quick_widgets.QuickWidget.__init__(self, host, target, profiles=profiles) + assert type_ in (C.CHAT_ONE2ONE, C.CHAT_GROUP) + if type_ == C.CHAT_GROUP and target.resource: + raise ValueError("A group chat entity can't have a resource") + self.current_target = target self.type = type_ - self.id = "" + self.id = "" # FIXME: to be removed self.nick = None self.occupants = set() + self.games = {} - def setType(self, type_): - """Set the type of the chat - @param type: can be 'one2one' for single conversation or 'group' for chat à la IRC + def __str__(self): + return u"Chat Widget [target: {}, type: {}, profile: {}]".format(self.target, self.type, self.profile) + + @staticmethod + def getWidgetHash(target, profile): + return (unicode(profile), target.bare) + + @staticmethod + def getPrivateHash(target, profile): + """Get unique hash for private conversations + + This method should be used with force_hash to get unique widget for private MUC conversations """ - self.type = type_ + return (unicode(profile), target) + + + def addTarget(self, target): + super(QuickChat, self).addTarget(target) + if target.resource: + self.current_target = target # FIXME: tmp, must use resource priority throught contactList instead + + @property + def target(self): + if self.type == C.CHAT_GROUP: + return self.current_target.bare + return self.current_target + + def manageMessage(self, entity, mess_type): + """Tell if this chat widget manage an entity and message type couple + + @param entity (jid.JID): (full) jid of the sending entity + @param mess_type (str): message type as given by newMessage + @return (bool): True if this Chat Widget manage this couple + """ + if self.type == C.CHAT_GROUP: + if mess_type == C.MESS_TYPE_GROUPCHAT and self.target == entity.bare: + return True + else: + if mess_type != C.MESS_TYPE_GROUPCHAT and entity in self.targets: + return True + return False def setPresents(self, nicks): - """Set the users presents in the contact list for a group chat - @param nicks: list of nicknames + """Set the occupants of a group chat. + + @param nicks (list[unicode]): sorted list of nicknames """ - log.debug (_("Adding users %s to room") % nicks) - if self.type != "group": - log.error (_("[INTERNAL] trying to set presents nicks for a non group chat window")) - raise Exception("INTERNAL ERROR") #TODO: raise proper Exception here + log.debug(_("Adding users %s to room") % nicks) + if self.type != C.CHAT_GROUP: + log.error(_("[INTERNAL] trying to set presents nicks for a non group chat window")) + raise Exception("INTERNAL ERROR") # TODO: raise proper Exception here self.occupants.update(nicks) def replaceUser(self, nick, show_info=True): """Add user if it is not in the group list""" log.debug (_("Replacing user %s") % nick) - if self.type != "group": + if self.type != C.CHAT_GROUP: log.error (_("[INTERNAL] trying to replace user for a non group chat window")) raise Exception("INTERNAL ERROR") #TODO: raise proper Exception here len_before = len(self.occupants) @@ -65,7 +116,7 @@ def removeUser(self, nick, show_info=True): """Remove a user from the group list""" log.debug(_("Removing user %s") % nick) - if self.type != "group": + if self.type != C.CHAT_GROUP: log.error (_("[INTERNAL] trying to remove user for a non group chat window")) raise Exception("INTERNAL ERROR") #TODO: raise proper Exception here self.occupants.remove(nick) @@ -82,7 +133,7 @@ def changeUserNick(self, old_nick, new_nick): """Change nick of a user in group list""" log.debug(_("Changing nick of user %(old_nick)s to %(new_nick)s") % {"old_nick": old_nick, "new_nick": new_nick}) - if self.type != "group": + if self.type != C.CHAT_GROUP: log.error (_("[INTERNAL] trying to change user nick for a non group chat window")) raise Exception("INTERNAL ERROR") #TODO: raise proper Exception here self.removeUser(old_nick, show_info=False) @@ -92,7 +143,7 @@ def setSubject(self, subject): """Set title for a group chat""" log.debug(_("Setting subject to %s") % subject) - if self.type != "group": + if self.type != C.CHAT_GROUP: log.error (_("[INTERNAL] trying to set subject for a non group chat window")) raise Exception("INTERNAL ERROR") #TODO: raise proper Exception here @@ -106,71 +157,97 @@ @param search (str): pattern to filter the history results @param profile (str): %(doc_profile)s """ - log.debug(_("now we print the history (%d messages)") % size) + log_msg = _(u"now we print the history") + if size != C.HISTORY_LIMIT_DEFAULT: + log_msg += _(u" (%d messages)" % size) + log.debug(log_msg) def onHistory(history): for line in history: - timestamp, from_jid, to_jid, message, _type, extra = line - if ((self.type == 'group' and _type != 'groupchat') or - (self.type == 'one2one' and _type == 'groupchat')): + timestamp, from_jid, to_jid, message, type_, extra = line # FIXME: extra is unused ! + if ((self.type == C.CHAT_GROUP and type_ != C.MESS_TYPE_GROUPCHAT) or + (self.type == C.CHAT_ONE2ONE and type_ == C.MESS_TYPE_GROUPCHAT)): continue - self.printMessage(JID(from_jid), message, profile, timestamp) + self.printMessage(jid.JID(from_jid), message, {'timestamp':timestamp}, profile) self.afterHistoryPrint() def onHistoryError(err): log.error(_("Can't get history")) - if self.target.startswith(C.PRIVATE_PREFIX): - target = unescapePrivate(self.target) - else: - target = self.target.bare + target = self.target.bare + + self.host.bridge.getHistory(unicode(self.host.profiles[profile].whoami.bare), unicode(target), size, True, search, profile, callback=onHistory, errback=onHistoryError) - return self.host.bridge.getHistory(self.host.profiles[profile]['whoami'].bare, target, size, search=search, profile=profile, callback=onHistory, errback=onHistoryError) + def _get_nick(self, entity): + """Return nick of this entity when possible""" + if self.type == C.CHAT_GROUP: + return entity.resource + contact_list = self.host.contact_lists[self.profile] + if entity.bare in contact_list: + return contact_list.getCache(entity,'nick') or contact_list.getCache(entity,'name') or entity.node or entity + return entity.node or entity + + def onPrivateCreated(self, widget): + """Method called when a new widget for private conversation (MUC) is created""" + raise NotImplementedError + + def getOrCreatePrivateWidget(self, entity): + """Create a widget for private conversation, or get it if it already exists - def _get_nick(self, jid): - """Return nick of this jid when possible""" - if self.target.startswith(C.PRIVATE_PREFIX): - unescaped = unescapePrivate(self.target) - if jid.startswith(C.PRIVATE_PREFIX) or unescaped.bare == jid.bare: - return unescaped.resource - return jid.resource if self.type == "group" else (self.host.contact_list.getCache(jid,'nick') or self.host.contact_list.getCache(jid,'name') or jid.node) + @param entity: full jid of the target + """ + return self.host.widgets.getOrCreateWidget(QuickChat, entity, type_=C.CHAT_ONE2ONE, force_hash=self.getPrivateHash(self.profile, entity), on_new_widget=self.onPrivateCreated, profile=self.profile) # we force hash to have a new widget, not this one again - def printMessage(self, from_jid, msg, profile, timestamp=None): + def newMessage(self, from_jid, target, msg, type_, extra, profile): + if self.type == C.CHAT_GROUP and target.resource and type_ != C.MESS_TYPE_GROUPCHAT: + # we have a private message, we forward it to a private conversation widget + chat_widget = self.getOrCreatePrivateWidget(target) + chat_widget.newMessage(from_jid, target, msg, type_, extra, profile) + else: + if type_ == C.MESS_TYPE_INFO: + self.printInfo(msg, extra=extra) + else: + self.printMessage(from_jid, msg, extra, profile) + + def printMessage(self, from_jid, msg, extra=None, profile=C.PROF_KEY_NONE): """Print message in chat window. Must be implemented by child class""" - jid = JID(from_jid) - nick = self._get_nick(jid) - mymess = (jid.resource == self.nick) if self.type == "group" else (jid.bare == self.host.profiles[profile]['whoami'].bare) #mymess = True if message comes from local user + nick = self._get_nick(from_jid) + mymess = (from_jid.resource == self.nick) if self.type == C.CHAT_GROUP else (from_jid.bare == self.host.profiles[profile].whoami.bare) #mymess = True if message comes from local user if msg.startswith('/me '): - self.printInfo('* %s %s' % (nick, msg[4:]), type_='me', timestamp=timestamp) + self.printInfo('* %s %s' % (nick, msg[4:]), type_='me', extra=extra) return - return jid, nick, mymess + return nick, mymess - def printInfo(self, msg, type_='normal', timestamp=None): + def printInfo(self, msg, type_='normal', extra=None): """Print general info @param msg: message to print @type_: one of: normal: general info like "toto has joined the room" me: "/me" information like "/me clenches his fist" ==> "toto clenches his fist" - @param timestamp (float): number of seconds since epoch + @param extra (dict): message data + """ + raise NotImplementedError + + def updateChatState(self, from_jid, state): + """Set the chat state (XEP-0085) of the contact. + + @param state: the new chat state """ raise NotImplementedError - def startGame(self, game_type, referee, players): - """Configure the chat window to start a game""" - #No need to raise an error as game are not mandatory - log.warning(_('startGame is not implemented in this frontend')) + def addGamePanel(self, widget): + """Insert a game panel to this Chat dialog. - def getGame(self, game_type): - """Return class managing the game type""" - #No need to raise an error as game are not mandatory - log.warning(_('getGame is not implemented in this frontend')) - - def updateChatState(self, state, nick=None): - """Set the chat state (XEP-0085) of the contact. Leave nick to None - to set the state for a one2one conversation, or give a nickname or - C.ALL_OCCUPANTS to set the state of a participant within a MUC. - @param state: the new chat state - @param nick: None for one2one, the MUC user nick or ALL_OCCUPANTS + @param widget (Widget): the game panel """ raise NotImplementedError + def removeGamePanel(self, widget): + """Remove the game panel from this Chat dialog. + + @param widget (Widget): the game panel + """ + raise NotImplementedError + + +quick_widgets.register(QuickChat)