Mercurial > libervia-backend
comparison frontends/src/quick_frontend/quick_chat.py @ 1963:a2bc5089c2eb
backend, frontends: message refactoring (huge commit):
/!\ several features are temporarily disabled, like notifications in frontends
next step in refactoring, with the following changes:
- jp: updated jp message to follow changes in backend/bridge
- jp: added --lang, --subject, --subject_lang, and --type options to jp message + fixed unicode handling for jid
- quick_frontend (QuickApp, QuickChat):
- follow backend changes
- refactored chat, message are now handled in OrderedDict and uid are kept so they can be updated
- Message and Occupant classes handle metadata, so frontend just have to display them
- Primitivus (Chat):
- follow backend/QuickFrontend changes
- info & standard messages are handled in the same MessageWidget class
- improved/simplified handling of messages, removed update() method
- user joined/left messages are merged when next to each other
- a separator is shown when message is received while widget is out of focus, so user can quickly see the new messages
- affiliation/role are shown (in a basic way for now) in occupants panel
- removed "/me" messages handling, as it will be done by a backend plugin
- message language is displayed when available (only one language per message for now)
- fixed :history and :search commands
- core (constants): new constants for messages type, XML namespace, entity type
- core: *Message methods renamed to follow new code sytle (e.g. sendMessageToBridge => messageSendToBridge)
- core (messages handling): fixed handling of language
- core (messages handling): mes_data['from'] and ['to'] are now jid.JID
- core (core.xmpp): reorganised message methods, added getNick() method to client.roster
- plugin text commands: fixed plugin and adapted to new messages behaviour. client is now used in arguments instead of profile
- plugins: added information for cancellation reason in CancelError calls
- plugin XEP-0045: various improvments, but this plugin still need work:
- trigger is used to avoid message already handled by the plugin to be handled a second time
- changed the way to handle history, the last message from DB is checked and we request only messages since this one, in seconds (thanks Poezio folks :))
- subject reception is waited before sending the roomJoined signal, this way we are sure that everything including history is ready
- cmd_* method now follow the new convention with client instead of profile
- roomUserJoined and roomUserLeft messages are removed, the events are now handled with info message with a "ROOM_USER_JOINED" info subtype
- probably other forgotten stuffs :p
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 20 Jun 2016 18:41:53 +0200 |
parents | 633b5c21aefd |
children | 02d21a589be2 |
comparison
equal
deleted
inserted
replaced
1962:a45235d8dc93 | 1963:a2bc5089c2eb |
---|---|
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | 19 |
20 from sat.core.i18n import _ | 20 from sat.core.i18n import _ |
21 from sat.core.log import getLogger | 21 from sat.core.log import getLogger |
22 log = getLogger(__name__) | 22 log = getLogger(__name__) |
23 from sat_frontends.tools import jid | 23 from sat.core import exceptions |
24 from sat_frontends.quick_frontend import quick_widgets | 24 from sat_frontends.quick_frontend import quick_widgets |
25 from sat_frontends.quick_frontend.constants import Const as C | 25 from sat_frontends.quick_frontend.constants import Const as C |
26 from collections import OrderedDict | 26 from collections import OrderedDict |
27 from datetime import datetime | 27 from sat_frontends.tools import jid |
28 | |
29 ROOM_USER_JOINED = 'ROOM_USER_JOINED' | |
30 ROOM_USER_LEFT = 'ROOM_USER_LEFT' | |
31 ROOM_USER_MOVED = (ROOM_USER_JOINED, ROOM_USER_LEFT) | |
32 | |
33 # from datetime import datetime | |
28 | 34 |
29 try: | 35 try: |
30 # FIXME: to be removed when an acceptable solution is here | 36 # FIXME: to be removed when an acceptable solution is here |
31 unicode('') # XXX: unicode doesn't exist in pyjamas | 37 unicode('') # XXX: unicode doesn't exist in pyjamas |
32 except (TypeError, AttributeError): # Error raised is not the same depending on pyjsbuild options | 38 except (TypeError, AttributeError): # Error raised is not the same depending on pyjsbuild options |
33 unicode = str | 39 unicode = str |
34 | 40 |
41 # FIXME: day_format need to be settable (i18n) | |
42 | |
43 class Message(object): | |
44 """Message metadata""" | |
45 | |
46 def __init__(self, parent, uid, timestamp, from_jid, to_jid, msg, subject, type_, extra, profile): | |
47 self.parent = parent | |
48 self.profile = profile | |
49 self.uid = uid | |
50 self.timestamp = timestamp | |
51 self.from_jid = from_jid | |
52 self.to_jid = to_jid | |
53 self.message = msg | |
54 self.subject = subject | |
55 self.type = type_ | |
56 self.extra = extra | |
57 self.nick = self.getNick(from_jid) | |
58 # own_mess is True if message was sent by profile's jid | |
59 self.own_mess = (from_jid.resource == self.parent.nick) if self.parent.type == C.CHAT_GROUP else (from_jid.bare == self.host.profiles[profile].whoami.bare) | |
60 self.widgets = set() # widgets linked to this message | |
61 | |
62 @property | |
63 def host(self): | |
64 return self.parent.host | |
65 | |
66 @property | |
67 def info_type(self): | |
68 return self.extra.get('info_type') | |
69 | |
70 def getNick(self, entity): | |
71 """Return nick of an entity when possible""" | |
72 contact_list = self.host.contact_lists[self.profile] | |
73 if self.type == C.MESS_TYPE_INFO and self.info_type in ROOM_USER_MOVED: | |
74 try: | |
75 return self.extra['user_nick'] | |
76 except KeyError: | |
77 log.error(u"extra data is missing user nick for uid {}".format(self.uid)) | |
78 return "" | |
79 if self.parent.type == C.CHAT_GROUP or entity in contact_list.getSpecialExtras(C.CONTACT_SPECIAL_GROUP): | |
80 return entity.resource or "" | |
81 if entity.bare in contact_list: | |
82 return contact_list.getCache(entity, 'nick') or contact_list.getCache(entity, 'name') or entity.node or entity | |
83 return entity.node or entity | |
84 | |
85 | |
86 class Occupant(object): | |
87 """Occupant metadata""" | |
88 | |
89 def __init__(self, parent, data, profile): | |
90 self.parent = parent | |
91 self.profile = profile | |
92 self.nick = data['nick'] | |
93 self.entity = data.get('entity') | |
94 if not self.entity: | |
95 self.entity = jid.JID(u"{}/{}".format(parent.target.bare, self.nick)), | |
96 self.affiliation = data['affiliation'] | |
97 self.role = data['role'] | |
98 self.widgets = set() # widgets linked to this occupant | |
99 | |
100 @property | |
101 def host(self): | |
102 return self.parent.host | |
103 | |
35 | 104 |
36 class QuickChat(quick_widgets.QuickWidget): | 105 class QuickChat(quick_widgets.QuickWidget): |
37 | 106 |
38 visible_states = ['chat_state'] | 107 visible_states = ['chat_state'] |
39 | 108 |
40 def __init__(self, host, target, type_=C.CHAT_ONE2ONE, profiles=None): | 109 def __init__(self, host, target, type_=C.CHAT_ONE2ONE, occupants=None, subject=None, profiles=None): |
41 """ | 110 """ |
42 @param type_: can be C.CHAT_ONE2ONE for single conversation or C.CHAT_GROUP for chat à la IRC | 111 @param type_: can be C.CHAT_ONE2ONE for single conversation or C.CHAT_GROUP for chat à la IRC |
43 """ | 112 """ |
113 self.lang = '' # default language to use for messages | |
44 quick_widgets.QuickWidget.__init__(self, host, target, profiles=profiles) | 114 quick_widgets.QuickWidget.__init__(self, host, target, profiles=profiles) |
115 self._locked = False # True when we are waiting for history/search | |
116 # messageNew signals are cached when locked | |
117 self._cache = [] | |
45 assert type_ in (C.CHAT_ONE2ONE, C.CHAT_GROUP) | 118 assert type_ in (C.CHAT_ONE2ONE, C.CHAT_GROUP) |
46 if type_ == C.CHAT_GROUP and target.resource: | |
47 raise ValueError("A group chat entity can't have a resource") | |
48 self.current_target = target | 119 self.current_target = target |
49 self.type = type_ | 120 self.type = type_ |
50 self.id = "" # FIXME: to be removed | 121 if type_ == C.CHAT_GROUP: |
51 self.nick = None | 122 if target.resource: |
123 raise exceptions.InternalError(u"a group chat entity can't have a resource") | |
124 self.nick = None | |
125 self.occupants = {} | |
126 self.setOccupants(occupants) | |
127 else: | |
128 if occupants is not None: | |
129 raise exceptions.InternalError(u"only group chat can have occupants") | |
130 self.messages = OrderedDict() # key: uid, value: Message instance | |
52 self.games = {} # key=game name (unicode), value=instance of quick_games.RoomGame | 131 self.games = {} # key=game name (unicode), value=instance of quick_games.RoomGame |
53 | 132 self.subject = subject |
133 | |
134 def postInit(self): | |
135 """Method to be called by frontend after widget is initialised | |
136 | |
137 handle the display of history and subject | |
138 """ | |
54 self.historyPrint(profile=self.profile) | 139 self.historyPrint(profile=self.profile) |
140 if self.subject is not None: | |
141 self.setSubject(self.subject) | |
142 | |
143 ## Widget management ## | |
55 | 144 |
56 def __str__(self): | 145 def __str__(self): |
57 return u"Chat Widget [target: {}, type: {}, profile: {}]".format(self.target, self.type, self.profile) | 146 return u"Chat Widget [target: {}, type: {}, profile: {}]".format(self.target, self.type, self.profile) |
58 | 147 |
59 @staticmethod | 148 @staticmethod |
71 | 160 |
72 def addTarget(self, target): | 161 def addTarget(self, target): |
73 super(QuickChat, self).addTarget(target) | 162 super(QuickChat, self).addTarget(target) |
74 if target.resource: | 163 if target.resource: |
75 self.current_target = target # FIXME: tmp, must use resource priority throught contactList instead | 164 self.current_target = target # FIXME: tmp, must use resource priority throught contactList instead |
165 | |
166 def onPrivateCreated(self, widget): | |
167 """Method called when a new widget for private conversation (MUC) is created""" | |
168 raise NotImplementedError | |
169 | |
170 def getOrCreatePrivateWidget(self, entity): | |
171 """Create a widget for private conversation, or get it if it already exists | |
172 | |
173 @param entity: full jid of the target | |
174 """ | |
175 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 | |
76 | 176 |
77 @property | 177 @property |
78 def target(self): | 178 def target(self): |
79 if self.type == C.CHAT_GROUP: | 179 if self.type == C.CHAT_GROUP: |
80 return self.current_target.bare | 180 return self.current_target.bare |
81 return self.current_target | 181 return self.current_target |
82 | 182 |
83 @property | 183 ## occupants ## |
84 def occupants(self): | 184 |
85 """Return the occupants of a group chat (nicknames). | 185 def setOccupants(self, occupants): |
86 | 186 """set the whole list of occupants""" |
87 @return: set(unicode) | 187 assert len(self.occupants) == 0 |
88 """ | 188 for nick, data in occupants.iteritems(): |
89 if self.type != C.CHAT_GROUP: | 189 self.occupants[nick] = Occupant( |
90 return set() | 190 self, |
91 contact_list = self.host.contact_lists[self.profile] | 191 data, |
92 return contact_list.getCache(self.target, C.CONTACT_RESOURCES).keys() | 192 self.profile |
193 ) | |
194 | |
195 def addUser(self, occupant_data): | |
196 """Add user if it is not in the group list""" | |
197 occupant = Occupant( | |
198 self, | |
199 occupant_data, | |
200 self.profile | |
201 ) | |
202 self.occupants[occupant.nick] = occupant | |
203 return occupant | |
204 | |
205 def removeUser(self, occupant_data): | |
206 """Remove a user from the group list""" | |
207 nick = occupant_data['nick'] | |
208 try: | |
209 occupant = self.occupants.pop(nick) | |
210 except KeyError: | |
211 log.warning(u"Trying to remove an unknown occupant: {}".format(nick)) | |
212 else: | |
213 return occupant | |
214 | |
215 def setUserNick(self, nick): | |
216 """Set the nick of the user, usefull for e.g. change the color of the user""" | |
217 self.nick = nick | |
218 | |
219 def changeUserNick(self, old_nick, new_nick): | |
220 """Change nick of a user in group list""" | |
221 self.printInfo("%s is now known as %s" % (old_nick, new_nick)) | |
222 | |
223 ## Messages ## | |
93 | 224 |
94 def manageMessage(self, entity, mess_type): | 225 def manageMessage(self, entity, mess_type): |
95 """Tell if this chat widget manage an entity and message type couple | 226 """Tell if this chat widget manage an entity and message type couple |
96 | 227 |
97 @param entity (jid.JID): (full) jid of the sending entity | 228 @param entity (jid.JID): (full) jid of the sending entity |
98 @param mess_type (str): message type as given by messageNew | 229 @param mess_type (str): message type as given by messageNew |
99 @return (bool): True if this Chat Widget manage this couple | 230 @return (bool): True if this Chat Widget manage this couple |
100 """ | 231 """ |
101 if self.type == C.CHAT_GROUP: | 232 if self.type == C.CHAT_GROUP: |
102 if mess_type == C.MESS_TYPE_GROUPCHAT and self.target == entity.bare: | 233 if mess_type in (C.MESS_TYPE_GROUPCHAT, C.MESS_TYPE_INFO) and self.target == entity.bare: |
103 return True | 234 return True |
104 else: | 235 else: |
105 if mess_type != C.MESS_TYPE_GROUPCHAT and entity in self.targets: | 236 if mess_type != C.MESS_TYPE_GROUPCHAT and entity in self.targets: |
106 return True | 237 return True |
107 return False | 238 return False |
108 | 239 |
109 def addUser(self, nick): | 240 def updateHistory(self, size=C.HISTORY_LIMIT_DEFAULT, search='', profile='@NONE@'): |
110 """Add user if it is not in the group list""" | 241 """Called when history need to be recreated |
111 self.printInfo("=> %s has joined the room" % nick) | 242 |
112 | 243 Remove all message from history then call historyPrint |
113 def removeUser(self, nick): | 244 Must probably be overriden by frontend to clear widget |
114 """Remove a user from the group list""" | |
115 self.printInfo("<= %s has left the room" % nick) | |
116 | |
117 def setUserNick(self, nick): | |
118 """Set the nick of the user, usefull for e.g. change the color of the user""" | |
119 self.nick = nick | |
120 | |
121 def changeUserNick(self, old_nick, new_nick): | |
122 """Change nick of a user in group list""" | |
123 self.printInfo("%s is now known as %s" % (old_nick, new_nick)) | |
124 | |
125 def setSubject(self, subject): | |
126 """Set title for a group chat""" | |
127 log.debug(_("Setting subject to %s") % subject) | |
128 if self.type != C.CHAT_GROUP: | |
129 log.error (_("[INTERNAL] trying to set subject for a non group chat window")) | |
130 raise Exception("INTERNAL ERROR") #TODO: raise proper Exception here | |
131 | |
132 def afterHistoryPrint(self): | |
133 """Refresh or scroll down the focus after the history is printed""" | |
134 pass | |
135 | |
136 def historyPrint(self, size=C.HISTORY_LIMIT_DEFAULT, search='', profile='@NONE@'): | |
137 """Print the current history | |
138 | |
139 @param size (int): number of messages | 245 @param size (int): number of messages |
140 @param search (str): pattern to filter the history results | 246 @param search (str): pattern to filter the history results |
141 @param profile (str): %(doc_profile)s | 247 @param profile (str): %(doc_profile)s |
142 """ | 248 """ |
249 self._locked = True | |
250 self.messages.clear() | |
251 self.historyPrint(size, search, profile) | |
252 | |
253 def _onHistoryPrinted(self): | |
254 """Method called when history is printed (or failed) | |
255 | |
256 unlock the widget, and can be used to refresh or scroll down | |
257 the focus after the history is printed | |
258 """ | |
259 self._locked = False | |
260 for data in self._cache: | |
261 self.messageNew(*data) | |
262 | |
263 def historyPrint(self, size=C.HISTORY_LIMIT_DEFAULT, search='', profile='@NONE@'): | |
264 """Print the current history | |
265 | |
266 @param size (int): number of messages | |
267 @param search (str): pattern to filter the history results | |
268 @param profile (str): %(doc_profile)s | |
269 """ | |
270 if size == 0: | |
271 log.debug(u"Empty history requested, skipping") | |
272 self._onHistoryPrinted() | |
273 return | |
143 log_msg = _(u"now we print the history") | 274 log_msg = _(u"now we print the history") |
144 if size != C.HISTORY_LIMIT_DEFAULT: | 275 if size != C.HISTORY_LIMIT_DEFAULT: |
145 log_msg += _(u" (%d messages)" % size) | 276 log_msg += _(u" ({} messages)".format(size)) |
146 log.debug(log_msg) | 277 log.debug(log_msg) |
147 | 278 |
148 target = self.target.bare | 279 target = self.target.bare |
149 | 280 |
150 def _historyGetCb(history): | 281 def _historyGetCb(history): |
151 day_format = "%A, %d %b %Y" # to display the day change | 282 # day_format = "%A, %d %b %Y" # to display the day change |
152 previous_day = datetime.now().strftime(day_format) | 283 # previous_day = datetime.now().strftime(day_format) |
284 # message_day = datetime.fromtimestamp(timestamp).strftime(self.day_format) | |
285 # if previous_day != message_day: | |
286 # self.printDayChange(message_day) | |
287 # previous_day = message_day | |
153 for data in history: | 288 for data in history: |
154 uid, timestamp, from_jid, to_jid, message, subject, type_, extra = data # FIXME: extra is unused ! | 289 uid, timestamp, from_jid, to_jid, message, subject, type_, extra = data |
155 if ((self.type == C.CHAT_GROUP and type_ != C.MESS_TYPE_GROUPCHAT) or | 290 from_jid = jid.JID(from_jid) |
156 (self.type == C.CHAT_ONE2ONE and type_ == C.MESS_TYPE_GROUPCHAT)): | 291 to_jid = jid.JID(to_jid) |
157 continue | 292 # if ((self.type == C.CHAT_GROUP and type_ != C.MESS_TYPE_GROUPCHAT) or |
158 message_day = datetime.fromtimestamp(timestamp).strftime(day_format) | 293 # (self.type == C.CHAT_ONE2ONE and type_ == C.MESS_TYPE_GROUPCHAT)): |
159 if previous_day != message_day: | 294 # continue |
160 self.printDayChange(message_day) | 295 self.messages[uid] = Message(self, uid, timestamp, from_jid, to_jid, message, subject, type_, extra, profile) |
161 previous_day = message_day | 296 self._onHistoryPrinted() |
162 extra["timestamp"] = timestamp | |
163 self.messageNew(uid, timestamp, jid.JID(from_jid), target, message, subject, type_, extra, profile) | |
164 self.afterHistoryPrint() | |
165 | 297 |
166 def _historyGetEb(err): | 298 def _historyGetEb(err): |
167 log.error(_("Can't get history")) | 299 log.error(_(u"Can't get history")) |
300 self._onHistoryPrinted() | |
168 | 301 |
169 self.host.bridge.historyGet(unicode(self.host.profiles[profile].whoami.bare), unicode(target), size, True, search, profile, callback=_historyGetCb, errback=_historyGetEb) | 302 self.host.bridge.historyGet(unicode(self.host.profiles[profile].whoami.bare), unicode(target), size, True, search, profile, callback=_historyGetCb, errback=_historyGetEb) |
170 | 303 |
171 def _get_nick(self, entity): | 304 def messageNew(self, uid, timestamp, from_jid, to_jid, msg, subject, type_, extra, profile): |
172 """Return nick of this entity when possible""" | 305 log.debug(u"messageNew ==> {}".format((uid, timestamp, from_jid, to_jid, msg, subject, type_, extra, profile))) |
173 contact_list = self.host.contact_lists[self.profile] | 306 if self._locked: |
174 if self.type == C.CHAT_GROUP or entity in contact_list.getSpecialExtras(C.CONTACT_SPECIAL_GROUP): | 307 self._cache.append(uid, timestamp, from_jid, to_jid, msg, subject, type_, extra, profile) |
175 return entity.resource or "" | |
176 if entity.bare in contact_list: | |
177 return contact_list.getCache(entity, 'nick') or contact_list.getCache(entity, 'name') or entity.node or entity | |
178 return entity.node or entity | |
179 | |
180 def onPrivateCreated(self, widget): | |
181 """Method called when a new widget for private conversation (MUC) is created""" | |
182 raise NotImplementedError | |
183 | |
184 def getOrCreatePrivateWidget(self, entity): | |
185 """Create a widget for private conversation, or get it if it already exists | |
186 | |
187 @param entity: full jid of the target | |
188 """ | |
189 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 | |
190 | |
191 def messageNew(self, uid, timestamp, from_jid, target, msg, subject, type_, extra, profile): | |
192 try: | |
193 msg = msg.itervalues().next() # FIXME: tmp fix until message refactoring is finished (msg is now a dict) | |
194 except StopIteration: | |
195 log.warning(u"No message found (uid: {})".format(uid)) | |
196 msg = '' | |
197 if self.type == C.CHAT_GROUP and target.resource and type_ != C.MESS_TYPE_GROUPCHAT: | |
198 # we have a private message, we forward it to a private conversation widget | |
199 chat_widget = self.getOrCreatePrivateWidget(target) | |
200 chat_widget.messageNew(uid, timestamp, from_jid, target, msg, subject, type_, extra, profile) | |
201 return | 308 return |
202 | 309 if self.type == C.CHAT_GROUP: |
203 if type_ == C.MESS_TYPE_INFO: | 310 if to_jid.resource and type_ != C.MESS_TYPE_GROUPCHAT: |
204 self.printInfo(msg, extra=extra) | 311 # we have a private message, we forward it to a private conversation widget |
205 else: | 312 chat_widget = self.getOrCreatePrivateWidget(to_jid) |
206 nick = self._get_nick(from_jid) | 313 chat_widget.messageNew(uid, timestamp, from_jid, to_jid, msg, subject, type_, extra, profile) |
207 if msg.startswith('/me '): | 314 return |
208 self.printInfo('* {} {}'.format(nick, msg[4:]), type_='me', extra=extra) | 315 if type_ == C.MESS_TYPE_INFO: |
209 else: | 316 try: |
210 # my_message is True if message comes from local user | 317 info_type = extra['info_type'] |
211 my_message = (from_jid.resource == self.nick) if self.type == C.CHAT_GROUP else (from_jid.bare == self.host.profiles[profile].whoami.bare) | 318 except KeyError: |
212 self.printMessage(nick, my_message, msg, timestamp, extra, profile) | 319 pass |
213 # FIXME: to be checked/removed after message refactoring | 320 else: |
214 # if timestamp: | 321 user_data = {k[5:]:v for k,v in extra.iteritems() if k.startswith('user_')} |
215 self.afterHistoryPrint() | 322 if info_type == ROOM_USER_JOINED: |
216 | 323 self.addUser(user_data) |
217 def printMessage(self, nick, my_message, message, timestamp, extra=None, profile=C.PROF_KEY_NONE): | 324 elif info_type == ROOM_USER_LEFT: |
218 """Print message in chat window. | 325 self.removeUser(user_data) |
219 | 326 |
220 @param nick (unicode): author nick | 327 message = Message(self, uid, timestamp, from_jid, to_jid, msg, subject, type_, extra, profile) |
221 @param my_message (boolean): True if profile is the author | 328 self.messages[uid] = message |
222 @param message (unicode): message content | 329 |
223 @param extra (dict): extra data | 330 if 'received_timestamp' in extra: |
224 """ | 331 log.warning(u"Delayed message received after history, this should not happen") |
225 # FIXME: check/remove this if necessary (message refactoring) | 332 self.createMessage(message) |
226 # if not timestamp: | 333 |
227 # # XXX: do not send notifications for each line of the history being displayed | 334 def createMessage(self, message, append=False): |
228 # # FIXME: this must be changed in the future if the timestamp is passed with | 335 """Must be implemented by frontend to create and show a new message widget |
229 # # all messages and not only with the messages coming from the history. | 336 |
230 self.notify(nick, message) | 337 This is only called on messageNew, not on history. |
231 | 338 You need to override historyPrint to handle the later |
232 def printInfo(self, msg, type_='normal', extra=None): | 339 @param message(Message): message data |
233 """Print general info. | 340 """ |
234 | 341 raise NotImplementedError |
235 @param msg (unicode): message to print | |
236 @param type_ (unicode): | |
237 - 'normal': general info like "toto has joined the room" | |
238 - 'me': "/me" information like "/me clenches his fist" ==> "toto clenches his fist" | |
239 @param extra (dict): message data | |
240 """ | |
241 self.notify(msg=msg) | |
242 | 342 |
243 def notify(self, contact="somebody", msg=""): | 343 def notify(self, contact="somebody", msg=""): |
244 """Notify the user of a new message if the frontend doesn't have the focus. | 344 """Notify the user of a new message if the frontend doesn't have the focus. |
245 | 345 |
246 @param contact (unicode): contact who wrote to the users | 346 @param contact (unicode): contact who wrote to the users |
247 @param msg (unicode): the message that has been received | 347 @param msg (unicode): the message that has been received |
248 """ | 348 """ |
349 # FIXME: not called anymore after refactoring | |
249 raise NotImplemented | 350 raise NotImplemented |
250 | 351 |
251 def printDayChange(self, day): | 352 def printDayChange(self, day): |
252 """Display the day on a new line. | 353 """Display the day on a new line. |
253 | 354 |
254 @param day(unicode): day to display (or not if this method is not overwritten) | 355 @param day(unicode): day to display (or not if this method is not overwritten) |
255 """ | 356 """ |
357 # FIXME: not called anymore after refactoring | |
256 pass | 358 pass |
257 | 359 |
258 def getEntityStates(self, entity): | 360 ## Room ## |
259 """Retrieve states for an entity. | 361 |
260 | 362 def setSubject(self, subject): |
261 @param entity (jid.JID): entity | 363 """Set title for a group chat""" |
262 @return: OrderedDict{unicode: unicode} | 364 self.subject = subject |
263 """ | 365 if self.type != C.CHAT_GROUP: |
264 states = OrderedDict() | 366 raise exceptions.InternalError("trying to set subject for a non group chat window") |
265 clist = self.host.contact_lists[self.profile] | |
266 for key in self.visible_states: | |
267 value = clist.getCache(entity, key) | |
268 if value: | |
269 states[key] = value | |
270 return states | |
271 | 367 |
272 def addGamePanel(self, widget): | 368 def addGamePanel(self, widget): |
273 """Insert a game panel to this Chat dialog. | 369 """Insert a game panel to this Chat dialog. |
274 | 370 |
275 @param widget (Widget): the game panel | 371 @param widget (Widget): the game panel |