Initial import to Tizen
[profile/ivi/python-twisted.git] / twisted / words / im / basechat.py
1 # -*- test-case-name: twisted.words.test.test_basechat -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5 """
6 Base classes for Instance Messenger clients.
7 """
8
9 from twisted.words.im.locals import OFFLINE, ONLINE, AWAY
10
11
12 class ContactsList:
13     """
14     A GUI object that displays a contacts list.
15
16     @ivar chatui: The GUI chat client associated with this contacts list.
17     @type chatui: L{ChatUI}
18
19     @ivar contacts: The contacts.
20     @type contacts: C{dict} mapping C{str} to a L{IPerson<interfaces.IPerson>}
21         provider
22
23     @ivar onlineContacts: The contacts who are currently online (have a status
24         that is not C{OFFLINE}).
25     @type onlineContacts: C{dict} mapping C{str} to a
26         L{IPerson<interfaces.IPerson>} provider
27
28     @ivar clients: The signed-on clients.
29     @type clients: C{list} of L{IClient<interfaces.IClient>} providers
30     """
31     def __init__(self, chatui):
32         """
33         @param chatui: The GUI chat client associated with this contacts list.
34         @type chatui: L{ChatUI}
35         """
36         self.chatui = chatui
37         self.contacts = {}
38         self.onlineContacts = {}
39         self.clients = []
40
41
42     def setContactStatus(self, person):
43         """
44         Inform the user that a person's status has changed.
45
46         @param person: The person whose status has changed.
47         @type person: L{IPerson<interfaces.IPerson>} provider
48         """
49         if not self.contacts.has_key(person.name):
50             self.contacts[person.name] = person
51         if not self.onlineContacts.has_key(person.name) and \
52                 (person.status == ONLINE or person.status == AWAY):
53             self.onlineContacts[person.name] = person
54         if self.onlineContacts.has_key(person.name) and \
55                 person.status == OFFLINE:
56             del self.onlineContacts[person.name]
57
58
59     def registerAccountClient(self, client):
60         """
61         Notify the user that an account client has been signed on to.
62
63         @param client: The client being added to your list of account clients.
64         @type client: L{IClient<interfaces.IClient>} provider
65         """
66         if not client in self.clients:
67             self.clients.append(client)
68
69
70     def unregisterAccountClient(self, client):
71         """
72         Notify the user that an account client has been signed off or
73         disconnected from.
74
75         @param client: The client being removed from the list of account
76             clients.
77         @type client: L{IClient<interfaces.IClient>} provider
78         """
79         if client in self.clients:
80             self.clients.remove(client)
81
82
83     def contactChangedNick(self, person, newnick):
84         """
85         Update your contact information to reflect a change to a contact's
86         nickname.
87
88         @param person: The person in your contacts list whose nickname is
89             changing.
90         @type person: L{IPerson<interfaces.IPerson>} provider
91
92         @param newnick: The new nickname for this person.
93         @type newnick: C{str}
94         """
95         oldname = person.name
96         if self.contacts.has_key(oldname):
97             del self.contacts[oldname]
98             person.name = newnick
99             self.contacts[newnick] = person
100             if self.onlineContacts.has_key(oldname):
101                 del self.onlineContacts[oldname]
102                 self.onlineContacts[newnick] = person
103
104
105
106 class Conversation:
107     """
108     A GUI window of a conversation with a specific person.
109
110     @ivar person: The person who you're having this conversation with.
111     @type person: L{IPerson<interfaces.IPerson>} provider
112
113     @ivar chatui: The GUI chat client associated with this conversation.
114     @type chatui: L{ChatUI}
115     """
116     def __init__(self, person, chatui):
117         """
118         @param person: The person who you're having this conversation with.
119         @type person: L{IPerson<interfaces.IPerson>} provider
120
121         @param chatui: The GUI chat client associated with this conversation.
122         @type chatui: L{ChatUI}
123         """
124         self.chatui = chatui
125         self.person = person
126
127
128     def show(self):
129         """
130         Display the ConversationWindow.
131         """
132         raise NotImplementedError("Subclasses must implement this method")
133
134
135     def hide(self):
136         """
137         Hide the ConversationWindow.
138         """
139         raise NotImplementedError("Subclasses must implement this method")
140
141
142     def sendText(self, text):
143         """
144         Send text to the person with whom the user is conversing.
145
146         @param text: The text to be sent.
147         @type text: C{str}
148         """
149         self.person.sendMessage(text, None)
150
151
152     def showMessage(self, text, metadata=None):
153         """
154         Display a message sent from the person with whom the user is conversing.
155
156         @param text: The sent message.
157         @type text: C{str}
158
159         @param metadata: Metadata associated with this message.
160         @type metadata: C{dict}
161         """
162         raise NotImplementedError("Subclasses must implement this method")
163
164
165     def contactChangedNick(self, person, newnick):
166         """
167         Change a person's name.
168
169         @param person: The person whose nickname is changing.
170         @type person: L{IPerson<interfaces.IPerson>} provider
171
172         @param newnick: The new nickname for this person.
173         @type newnick: C{str}
174         """
175         self.person.name = newnick
176
177
178
179 class GroupConversation:
180     """
181     A GUI window of a conversation with a group of people.
182
183     @ivar chatui: The GUI chat client associated with this conversation.
184     @type chatui: L{ChatUI}
185
186     @ivar group: The group of people that are having this conversation.
187     @type group: L{IGroup<interfaces.IGroup>} provider
188
189     @ivar members: The names of the people in this conversation.
190     @type members: C{list} of C{str}
191     """
192     def __init__(self, group, chatui):
193         """
194         @param chatui: The GUI chat client associated with this conversation.
195         @type chatui: L{ChatUI}
196
197         @param group: The group of people that are having this conversation.
198         @type group: L{IGroup<interfaces.IGroup>} provider
199         """
200         self.chatui = chatui
201         self.group = group
202         self.members = []
203
204
205     def show(self):
206         """
207         Display the GroupConversationWindow.
208         """
209         raise NotImplementedError("Subclasses must implement this method")
210
211
212     def hide(self):
213         """
214         Hide the GroupConversationWindow.
215         """
216         raise NotImplementedError("Subclasses must implement this method")
217
218
219     def sendText(self, text):
220         """
221         Send text to the group.
222
223         @param: The text to be sent.
224         @type text: C{str}
225         """
226         self.group.sendGroupMessage(text, None)
227
228
229     def showGroupMessage(self, sender, text, metadata=None):
230         """
231         Display to the user a message sent to this group from the given sender.
232
233         @param sender: The person sending the message.
234         @type sender: C{str}
235
236         @param text: The sent message.
237         @type text: C{str}
238
239         @param metadata: Metadata associated with this message.
240         @type metadata: C{dict}
241         """
242         raise NotImplementedError("Subclasses must implement this method")
243
244
245     def setGroupMembers(self, members):
246         """
247         Set the list of members in the group.
248
249         @param members: The names of the people that will be in this group.
250         @type members: C{list} of C{str}
251         """
252         self.members = members
253
254
255     def setTopic(self, topic, author):
256         """
257         Change the topic for the group conversation window and display this
258         change to the user.
259
260         @param topic: This group's topic.
261         @type topic: C{str}
262
263         @param author: The person changing the topic.
264         @type author: C{str}
265         """
266         raise NotImplementedError("Subclasses must implement this method")
267
268
269     def memberJoined(self, member):
270         """
271         Add the given member to the list of members in the group conversation
272         and displays this to the user.
273
274         @param member: The person joining the group conversation.
275         @type member: C{str}
276         """
277         if not member in self.members:
278             self.members.append(member)
279
280
281     def memberChangedNick(self, oldnick, newnick):
282         """
283         Change the nickname for a member of the group conversation and displays
284         this change to the user.
285
286         @param oldnick: The old nickname.
287         @type oldnick: C{str}
288
289         @param newnick: The new nickname.
290         @type newnick: C{str}
291         """
292         if oldnick in self.members:
293             self.members.remove(oldnick)
294             self.members.append(newnick)
295
296
297     def memberLeft(self, member):
298         """
299         Delete the given member from the list of members in the group
300         conversation and displays the change to the user.
301
302         @param member: The person leaving the group conversation.
303         @type member: C{str}
304         """
305         if member in self.members:
306             self.members.remove(member)
307
308
309
310 class ChatUI:
311     """
312     A GUI chat client.
313
314     @type conversations: C{dict} of L{Conversation}
315     @ivar conversations: A cache of all the direct windows.
316
317     @type groupConversations: C{dict} of L{GroupConversation}
318     @ivar groupConversations: A cache of all the group windows.
319
320     @type persons: C{dict} with keys that are a C{tuple} of (C{str},
321        L{IAccount<interfaces.IAccount>} provider) and values that are
322        L{IPerson<interfaces.IPerson>} provider
323     @ivar persons: A cache of all the users associated with this client.
324
325     @type groups: C{dict} with keys that are a C{tuple} of (C{str},
326         L{IAccount<interfaces.IAccount>} provider) and values that are
327         L{IGroup<interfaces.IGroup>} provider
328     @ivar groups: A cache of all the groups associated with this client.
329
330     @type onlineClients: C{list} of L{IClient<interfaces.IClient>} providers
331     @ivar onlineClients: A list of message sources currently online.
332
333     @type contactsList: L{ContactsList}
334     @ivar contactsList: A contacts list.
335     """
336     def __init__(self):
337         self.conversations = {}
338         self.groupConversations = {}
339         self.persons = {}
340         self.groups = {}
341         self.onlineClients = []
342         self.contactsList = ContactsList(self)
343
344
345     def registerAccountClient(self, client):
346         """
347         Notify the user that an account has been signed on to.
348
349         @type client: L{IClient<interfaces.IClient>} provider
350         @param client: The client account for the person who has just signed on.
351
352         @rtype client: L{IClient<interfaces.IClient>} provider
353         @return: The client, so that it may be used in a callback chain.
354         """
355         self.onlineClients.append(client)
356         self.contactsList.registerAccountClient(client)
357         return client
358
359
360     def unregisterAccountClient(self, client):
361         """
362         Notify the user that an account has been signed off or disconnected.
363
364         @type client: L{IClient<interfaces.IClient>} provider
365         @param client: The client account for the person who has just signed
366             off.
367         """
368         self.onlineClients.remove(client)
369         self.contactsList.unregisterAccountClient(client)
370
371
372     def getContactsList(self):
373         """
374         Get the contacts list associated with this chat window.
375
376         @rtype: L{ContactsList}
377         @return: The contacts list associated with this chat window.
378         """
379         return self.contactsList
380
381
382     def getConversation(self, person, Class=Conversation, stayHidden=False):
383         """
384         For the given person object, return the conversation window or create
385         and return a new conversation window if one does not exist.
386
387         @type person: L{IPerson<interfaces.IPerson>} provider
388         @param person: The person whose conversation window we want to get.
389
390         @type Class: L{IConversation<interfaces.IConversation>} implementor
391         @param: The kind of conversation window we want. If the conversation
392             window for this person didn't already exist, create one of this type.
393
394         @type stayHidden: C{bool}
395         @param stayHidden: Whether or not the conversation window should stay
396             hidden.
397
398         @rtype: L{IConversation<interfaces.IConversation>} provider
399         @return: The conversation window.
400         """
401         conv = self.conversations.get(person)
402         if not conv:
403             conv = Class(person, self)
404             self.conversations[person] = conv
405         if stayHidden:
406             conv.hide()
407         else:
408             conv.show()
409         return conv
410
411
412     def getGroupConversation(self, group, Class=GroupConversation,
413                              stayHidden=False):
414         """
415         For the given group object, return the group conversation window or
416         create and return a new group conversation window if it doesn't exist.
417
418         @type group: L{IGroup<interfaces.IGroup>} provider
419         @param group: The group whose conversation window we want to get.
420
421         @type Class: L{IConversation<interfaces.IConversation>} implementor
422         @param: The kind of conversation window we want. If the conversation
423             window for this person didn't already exist, create one of this type.
424
425         @type stayHidden: C{bool}
426         @param stayHidden: Whether or not the conversation window should stay
427             hidden.
428
429         @rtype: L{IGroupConversation<interfaces.IGroupConversation>} provider
430         @return: The group conversation window.
431         """
432         conv = self.groupConversations.get(group)
433         if not conv:
434             conv = Class(group, self)
435             self.groupConversations[group] = conv
436         if stayHidden:
437             conv.hide()
438         else:
439             conv.show()
440         return conv
441
442
443     def getPerson(self, name, client):
444         """
445         For the given name and account client, return an instance of a
446         L{IGroup<interfaces.IPerson>} provider or create and return a new
447         instance of a L{IGroup<interfaces.IPerson>} provider.
448
449         @type name: C{str}
450         @param name: The name of the person of interest.
451
452         @type client: L{IClient<interfaces.IClient>} provider
453         @param client: The client account of interest.
454
455         @rtype: L{IPerson<interfaces.IPerson>} provider
456         @return: The person with that C{name}.
457         """
458         account = client.account
459         p = self.persons.get((name, account))
460         if not p:
461             p = account.getPerson(name)
462             self.persons[name, account] = p
463         return p
464
465
466     def getGroup(self, name, client):
467         """
468         For the given name and account client, return an instance of a
469         L{IGroup<interfaces.IGroup>} provider or create and return a new instance
470         of a L{IGroup<interfaces.IGroup>} provider.
471
472         @type name: C{str}
473         @param name: The name of the group of interest.
474
475         @type client: L{IClient<interfaces.IClient>} provider
476         @param client: The client account of interest.
477
478         @rtype: L{IGroup<interfaces.IGroup>} provider
479         @return: The group with that C{name}.
480         """
481         # I accept 'client' instead of 'account' in my signature for
482         # backwards compatibility.  (Groups changed to be Account-oriented
483         # in CVS revision 1.8.)
484         account = client.account
485         g = self.groups.get((name, account))
486         if not g:
487             g = account.getGroup(name)
488             self.groups[name, account] = g
489         return g
490
491
492     def contactChangedNick(self, person, newnick):
493         """
494         For the given C{person}, change the C{person}'s C{name} to C{newnick}
495         and tell the contact list and any conversation windows with that
496         C{person} to change as well.
497
498         @type person: L{IPerson<interfaces.IPerson>} provider
499         @param person: The person whose nickname will get changed.
500
501         @type newnick: C{str}
502         @param newnick: The new C{name} C{person} will take.
503         """
504         oldnick = person.name
505         if self.persons.has_key((oldnick, person.account)):
506             conv = self.conversations.get(person)
507             if conv:
508                 conv.contactChangedNick(person, newnick)
509             self.contactsList.contactChangedNick(person, newnick)
510             del self.persons[oldnick, person.account]
511             person.name = newnick
512             self.persons[person.name, person.account] = person