1
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
2
# See LICENSE for details.
6
"""Base classes for Instance Messenger clients."""
8
from twisted.words.im.locals import OFFLINE, ONLINE, AWAY
11
"""A GUI object that displays a contacts list"""
12
def __init__(self, chatui):
15
@type chatui: L{ChatUI}
19
self.onlineContacts = {}
22
def setContactStatus(self, person):
23
"""Inform the user that a person's status has changed.
25
@type person: L{Person<interfaces.IPerson>}
27
if not self.contacts.has_key(person.name):
28
self.contacts[person.name] = person
29
if not self.onlineContacts.has_key(person.name) and \
30
(person.status == ONLINE or person.status == AWAY):
31
self.onlineContacts[person.name] = person
32
if self.onlineContacts.has_key(person.name) and \
33
person.status == OFFLINE:
34
del self.onlineContacts[person.name]
36
def registerAccountClient(self, client):
37
"""Notify the user that an account client has been signed on to.
39
@type client: L{Client<interfaces.IClient>}
41
if not client in self.clients:
42
self.clients.append(client)
44
def unregisterAccountClient(self, client):
45
"""Notify the user that an account client has been signed off
48
@type client: L{Client<interfaces.IClient>}
50
if client in self.clients:
51
self.clients.remove(client)
53
def contactChangedNick(self, person, newnick):
55
if self.contacts.has_key(oldname):
56
del self.contacts[oldname]
58
self.contacts[newnick] = person
59
if self.onlineContacts.has_key(oldname):
60
del self.onlineContacts[oldname]
61
self.onlineContacts[newnick] = person
65
"""A GUI window of a conversation with a specific person"""
66
def __init__(self, person, chatui):
68
@type person: L{Person<interfaces.IPerson>}
69
@type chatui: L{ChatUI}
75
"""Displays the ConversationWindow"""
76
raise NotImplementedError("Subclasses must implement this method")
79
"""Hides the ConversationWindow"""
80
raise NotImplementedError("Subclasses must implement this method")
82
def sendText(self, text):
83
"""Sends text to the person with whom the user is conversing.
85
@returntype: L{Deferred<twisted.internet.defer.Deferred>}
87
self.person.sendMessage(text, None)
89
def showMessage(self, text, metadata=None):
90
"""Display a message sent from the person with whom she is conversing
95
raise NotImplementedError("Subclasses must implement this method")
97
def contactChangedNick(self, person, newnick):
98
"""Change a person's name.
100
@type person: L{Person<interfaces.IPerson>}
101
@type newnick: string
103
self.person.name = newnick
106
class GroupConversation:
107
"""A conversation with a group of people."""
108
def __init__(self, group, chatui):
110
@type group: L{Group<interfaces.IGroup>}
112
@type chatui: L{ChatUI}
119
"""Displays the GroupConversationWindow."""
120
raise NotImplementedError("Subclasses must implement this method")
123
"""Hides the GroupConversationWindow."""
124
raise NotImplementedError("Subclasses must implement this method")
126
def sendText(self, text):
127
"""Sends text to the group.
130
@returntype: L{Deferred<twisted.internet.defer.Deferred>}
132
self.group.sendGroupMessage(text, None)
134
def showGroupMessage(self, sender, text, metadata=None):
135
"""Displays to the user a message sent to this group from the given sender
136
@type sender: string (XXX: Not Person?)
140
raise NotImplementedError("Subclasses must implement this method")
142
def setGroupMembers(self, members):
143
"""Sets the list of members in the group and displays it to the user
145
self.members = members
147
def setTopic(self, topic, author):
148
"""Displays the topic (from the server) for the group conversation window
151
@type author: string (XXX: Not Person?)
153
raise NotImplementedError("Subclasses must implement this method")
155
def memberJoined(self, member):
156
"""Adds the given member to the list of members in the group conversation
157
and displays this to the user
159
@type member: string (XXX: Not Person?)
161
if not member in self.members:
162
self.members.append(member)
164
def memberChangedNick(self, oldnick, newnick):
165
"""Changes the oldnick in the list of members to newnick and displays this
168
@type oldnick: string
169
@type newnick: string
171
if oldnick in self.members:
172
self.members.remove(oldnick)
173
self.members.append(newnick)
174
#self.chatui.contactChangedNick(oldnick, newnick)
176
def memberLeft(self, member):
177
"""Deletes the given member from the list of members in the group
178
conversation and displays the change to the user
182
if member in self.members:
183
self.members.remove(member)
187
"""A GUI chat client"""
189
self.conversations = {} # cache of all direct windows
190
self.groupConversations = {} # cache of all group windows
191
self.persons = {} # keys are (name, client)
192
self.groups = {} # cache of all groups
193
self.onlineClients = [] # list of message sources currently online
194
self.contactsList = ContactsList(self)
196
def registerAccountClient(self, client):
197
"""Notifies user that an account has been signed on to.
199
@type client: L{Client<interfaces.IClient>}
200
@returns: client, so that I may be used in a callback chain
202
print "signing onto", client.accountName
203
self.onlineClients.append(client)
204
self.contactsList.registerAccountClient(client)
207
def unregisterAccountClient(self, client):
208
"""Notifies user that an account has been signed off or disconnected
210
@type client: L{Client<interfaces.IClient>}
212
print "signing off from", client.accountName
213
self.onlineClients.remove(client)
214
self.contactsList.unregisterAccountClient(client)
216
def getContactsList(self):
218
@returntype: L{ContactsList}
220
return self.contactsList
222
def getConversation(self, person, Class=Conversation, stayHidden=0):
223
"""For the given person object, returns the conversation window
224
or creates and returns a new conversation window if one does not exist.
226
@type person: L{Person<interfaces.IPerson>}
227
@type Class: L{Conversation<interfaces.IConversation>} class
228
@type stayHidden: boolean
230
@returntype: L{Conversation<interfaces.IConversation>}
232
conv = self.conversations.get(person)
234
conv = Class(person, self)
235
self.conversations[person] = conv
242
def getGroupConversation(self,group,Class=GroupConversation,stayHidden=0):
243
"""For the given group object, returns the group conversation window or
244
creates and returns a new group conversation window if it doesn't exist
246
@type group: L{Group<interfaces.IGroup>}
247
@type Class: L{Conversation<interfaces.IConversation>} class
248
@type stayHidden: boolean
250
@returntype: L{GroupConversation<interfaces.IGroupConversation>}
252
conv = self.groupConversations.get(group)
254
conv = Class(group, self)
255
self.groupConversations[group] = conv
262
def getPerson(self, name, client):
263
"""For the given name and account client, returns the instance of the
264
AbstractPerson subclass, or creates and returns a new AbstractPerson
265
subclass of the type Class
268
@type client: L{Client<interfaces.IClient>}
270
@returntype: L{Person<interfaces.IPerson>}
272
account = client.account
273
p = self.persons.get((name, account))
275
p = account.getPerson(name)
276
self.persons[name, account] = p
279
def getGroup(self, name, client):
280
"""For the given name and account client, returns the instance of the
281
AbstractGroup subclass, or creates and returns a new AbstractGroup
282
subclass of the type Class
285
@type client: L{Client<interfaces.IClient>}
287
@returntype: L{Group<interfaces.IGroup>}
289
# I accept 'client' instead of 'account' in my signature for
290
# backwards compatibility. (Groups changed to be Account-oriented
291
# in CVS revision 1.8.)
292
account = client.account
293
g = self.groups.get((name, account))
295
g = account.getGroup(name)
296
self.groups[name, account] = g
299
def contactChangedNick(self, oldnick, newnick):
300
"""For the given person, changes the person's name to newnick, and
301
tells the contact list and any conversation windows with that person
304
@type oldnick: string
305
@type newnick: string
307
if self.persons.has_key((person.name, person.account)):
308
conv = self.conversations.get(person)
310
conv.contactChangedNick(person, newnick)
312
self.contactsList.contactChangedNick(person, newnick)
314
del self.persons[person.name, person.account]
315
person.name = newnick
316
self.persons[person.name, person.account] = person