OLD | NEW |
| (Empty) |
1 # Copyright (c) 2001-2004 Twisted Matrix Laboratories. | |
2 # See LICENSE for details. | |
3 | |
4 # | |
5 | |
6 """Base classes for Instance Messenger clients.""" | |
7 | |
8 from twisted.words.im.locals import OFFLINE, ONLINE, AWAY | |
9 | |
10 class ContactsList: | |
11 """A GUI object that displays a contacts list""" | |
12 def __init__(self, chatui): | |
13 """ | |
14 @param chatui: ??? | |
15 @type chatui: L{ChatUI} | |
16 """ | |
17 self.chatui = chatui | |
18 self.contacts = {} | |
19 self.onlineContacts = {} | |
20 self.clients = [] | |
21 | |
22 def setContactStatus(self, person): | |
23 """Inform the user that a person's status has changed. | |
24 | |
25 @type person: L{Person<interfaces.IPerson>} | |
26 """ | |
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] | |
35 | |
36 def registerAccountClient(self, client): | |
37 """Notify the user that an account client has been signed on to. | |
38 | |
39 @type client: L{Client<interfaces.IClient>} | |
40 """ | |
41 if not client in self.clients: | |
42 self.clients.append(client) | |
43 | |
44 def unregisterAccountClient(self, client): | |
45 """Notify the user that an account client has been signed off | |
46 or disconnected from. | |
47 | |
48 @type client: L{Client<interfaces.IClient>} | |
49 """ | |
50 if client in self.clients: | |
51 self.clients.remove(client) | |
52 | |
53 def contactChangedNick(self, person, newnick): | |
54 oldname = person.name | |
55 if self.contacts.has_key(oldname): | |
56 del self.contacts[oldname] | |
57 person.name = newnick | |
58 self.contacts[newnick] = person | |
59 if self.onlineContacts.has_key(oldname): | |
60 del self.onlineContacts[oldname] | |
61 self.onlineContacts[newnick] = person | |
62 | |
63 | |
64 class Conversation: | |
65 """A GUI window of a conversation with a specific person""" | |
66 def __init__(self, person, chatui): | |
67 """ | |
68 @type person: L{Person<interfaces.IPerson>} | |
69 @type chatui: L{ChatUI} | |
70 """ | |
71 self.chatui = chatui | |
72 self.person = person | |
73 | |
74 def show(self): | |
75 """Displays the ConversationWindow""" | |
76 raise NotImplementedError("Subclasses must implement this method") | |
77 | |
78 def hide(self): | |
79 """Hides the ConversationWindow""" | |
80 raise NotImplementedError("Subclasses must implement this method") | |
81 | |
82 def sendText(self, text): | |
83 """Sends text to the person with whom the user is conversing. | |
84 | |
85 @returntype: L{Deferred<twisted.internet.defer.Deferred>} | |
86 """ | |
87 self.person.sendMessage(text, None) | |
88 | |
89 def showMessage(self, text, metadata=None): | |
90 """Display a message sent from the person with whom she is conversing | |
91 | |
92 @type text: string | |
93 @type metadata: dict | |
94 """ | |
95 raise NotImplementedError("Subclasses must implement this method") | |
96 | |
97 def contactChangedNick(self, person, newnick): | |
98 """Change a person's name. | |
99 | |
100 @type person: L{Person<interfaces.IPerson>} | |
101 @type newnick: string | |
102 """ | |
103 self.person.name = newnick | |
104 | |
105 | |
106 class GroupConversation: | |
107 """A conversation with a group of people.""" | |
108 def __init__(self, group, chatui): | |
109 """ | |
110 @type group: L{Group<interfaces.IGroup>} | |
111 @param chatui: ??? | |
112 @type chatui: L{ChatUI} | |
113 """ | |
114 self.chatui = chatui | |
115 self.group = group | |
116 self.members = [] | |
117 | |
118 def show(self): | |
119 """Displays the GroupConversationWindow.""" | |
120 raise NotImplementedError("Subclasses must implement this method") | |
121 | |
122 def hide(self): | |
123 """Hides the GroupConversationWindow.""" | |
124 raise NotImplementedError("Subclasses must implement this method") | |
125 | |
126 def sendText(self, text): | |
127 """Sends text to the group. | |
128 | |
129 @type text: string | |
130 @returntype: L{Deferred<twisted.internet.defer.Deferred>} | |
131 """ | |
132 self.group.sendGroupMessage(text, None) | |
133 | |
134 def showGroupMessage(self, sender, text, metadata=None): | |
135 """Displays to the user a message sent to this group from the given send
er | |
136 @type sender: string (XXX: Not Person?) | |
137 @type text: string | |
138 @type metadata: dict | |
139 """ | |
140 raise NotImplementedError("Subclasses must implement this method") | |
141 | |
142 def setGroupMembers(self, members): | |
143 """Sets the list of members in the group and displays it to the user | |
144 """ | |
145 self.members = members | |
146 | |
147 def setTopic(self, topic, author): | |
148 """Displays the topic (from the server) for the group conversation windo
w | |
149 | |
150 @type topic: string | |
151 @type author: string (XXX: Not Person?) | |
152 """ | |
153 raise NotImplementedError("Subclasses must implement this method") | |
154 | |
155 def memberJoined(self, member): | |
156 """Adds the given member to the list of members in the group conversatio
n | |
157 and displays this to the user | |
158 | |
159 @type member: string (XXX: Not Person?) | |
160 """ | |
161 if not member in self.members: | |
162 self.members.append(member) | |
163 | |
164 def memberChangedNick(self, oldnick, newnick): | |
165 """Changes the oldnick in the list of members to newnick and displays th
is | |
166 change to the user | |
167 | |
168 @type oldnick: string | |
169 @type newnick: string | |
170 """ | |
171 if oldnick in self.members: | |
172 self.members.remove(oldnick) | |
173 self.members.append(newnick) | |
174 #self.chatui.contactChangedNick(oldnick, newnick) | |
175 | |
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 | |
179 | |
180 @type member: string | |
181 """ | |
182 if member in self.members: | |
183 self.members.remove(member) | |
184 | |
185 | |
186 class ChatUI: | |
187 """A GUI chat client""" | |
188 def __init__(self): | |
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) | |
195 | |
196 def registerAccountClient(self, client): | |
197 """Notifies user that an account has been signed on to. | |
198 | |
199 @type client: L{Client<interfaces.IClient>} | |
200 @returns: client, so that I may be used in a callback chain | |
201 """ | |
202 print "signing onto", client.accountName | |
203 self.onlineClients.append(client) | |
204 self.contactsList.registerAccountClient(client) | |
205 return client | |
206 | |
207 def unregisterAccountClient(self, client): | |
208 """Notifies user that an account has been signed off or disconnected | |
209 | |
210 @type client: L{Client<interfaces.IClient>} | |
211 """ | |
212 print "signing off from", client.accountName | |
213 self.onlineClients.remove(client) | |
214 self.contactsList.unregisterAccountClient(client) | |
215 | |
216 def getContactsList(self): | |
217 """ | |
218 @returntype: L{ContactsList} | |
219 """ | |
220 return self.contactsList | |
221 | |
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. | |
225 | |
226 @type person: L{Person<interfaces.IPerson>} | |
227 @type Class: L{Conversation<interfaces.IConversation>} class | |
228 @type stayHidden: boolean | |
229 | |
230 @returntype: L{Conversation<interfaces.IConversation>} | |
231 """ | |
232 conv = self.conversations.get(person) | |
233 if not conv: | |
234 conv = Class(person, self) | |
235 self.conversations[person] = conv | |
236 if stayHidden: | |
237 conv.hide() | |
238 else: | |
239 conv.show() | |
240 return conv | |
241 | |
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 | |
245 | |
246 @type group: L{Group<interfaces.IGroup>} | |
247 @type Class: L{Conversation<interfaces.IConversation>} class | |
248 @type stayHidden: boolean | |
249 | |
250 @returntype: L{GroupConversation<interfaces.IGroupConversation>} | |
251 """ | |
252 conv = self.groupConversations.get(group) | |
253 if not conv: | |
254 conv = Class(group, self) | |
255 self.groupConversations[group] = conv | |
256 if stayHidden: | |
257 conv.hide() | |
258 else: | |
259 conv.show() | |
260 return conv | |
261 | |
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 | |
266 | |
267 @type name: string | |
268 @type client: L{Client<interfaces.IClient>} | |
269 | |
270 @returntype: L{Person<interfaces.IPerson>} | |
271 """ | |
272 account = client.account | |
273 p = self.persons.get((name, account)) | |
274 if not p: | |
275 p = account.getPerson(name) | |
276 self.persons[name, account] = p | |
277 return p | |
278 | |
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 | |
283 | |
284 @type name: string | |
285 @type client: L{Client<interfaces.IClient>} | |
286 | |
287 @returntype: L{Group<interfaces.IGroup>} | |
288 """ | |
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)) | |
294 if not g: | |
295 g = account.getGroup(name) | |
296 self.groups[name, account] = g | |
297 return g | |
298 | |
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 | |
302 to change as well. | |
303 | |
304 @type oldnick: string | |
305 @type newnick: string | |
306 """ | |
307 if self.persons.has_key((person.name, person.account)): | |
308 conv = self.conversations.get(person) | |
309 if conv: | |
310 conv.contactChangedNick(person, newnick) | |
311 | |
312 self.contactsList.contactChangedNick(person, newnick) | |
313 | |
314 del self.persons[person.name, person.account] | |
315 person.name = newnick | |
316 self.persons[person.name, person.account] = person | |
OLD | NEW |