1 # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
2 # See LICENSE for details.
6 """Base classes for Instance Messenger clients."""
8 from Screens.Screen import Screen
10 from Components.Pixmap import *
11 from Components.Pixmap import Pixmap
12 from Components.ActionMap import ActionMap, NumberActionMap
13 from Components.ScrollLabel import ScrollLabel
14 from Components.GUIComponent import *
15 from Components.MenuList import MenuList
16 from Components.Input import Input
17 from Components.Label import Label
18 from Components.config import *
19 from Components.ConfigList import ConfigList
20 from Plugins.Plugin import PluginDescriptor
21 from Tools.NumericalTextInput import *
22 from Tools.Directories import *
24 from locals import OFFLINE, ONLINE, AWAY
27 from dreamIRCTools import *
28 #from myScrollLabel import *
29 #from dreamIRCMainMenu import *
32 """A GUI object that displays a contacts list"""
33 def __init__(self, chatui):
36 @type chatui: L{ChatUI}
40 self.onlineContacts = {}
43 def setContactStatus(self, person):
44 """Inform the user that a person's status has changed.
46 @type person: L{Person<interfaces.IPerson>}
48 if not self.contacts.has_key(person.name):
49 self.contacts[person.name] = person
50 if not self.onlineContacts.has_key(person.name) and \
51 (person.status == ONLINE or person.status == AWAY):
52 self.onlineContacts[person.name] = person
53 if self.onlineContacts.has_key(person.name) and \
54 person.status == OFFLINE:
55 del self.onlineContacts[person.name]
57 def registerAccountClient(self, client):
58 """Notify the user that an account client has been signed on to.
60 @type client: L{Client<interfaces.IClient>}
62 if not client in self.clients:
63 self.clients.append(client)
65 def unregisterAccountClient(self, client):
66 """Notify the user that an account client has been signed off
69 @type client: L{Client<interfaces.IClient>}
71 if client in self.clients:
72 self.clients.remove(client)
74 def contactChangedNick(self, person, newnick):
76 if self.contacts.has_key(oldname):
77 del self.contacts[oldname]
79 self.contacts[newnick] = person
80 if self.onlineContacts.has_key(oldname):
81 del self.onlineContacts[oldname]
82 self.onlineContacts[newnick] = person
86 """A GUI window of a conversation with a specific person"""
87 def __init__(self, person, chatui):
89 @type person: L{Person<interfaces.IPerson>}
90 @type chatui: L{ChatUI}
94 self.pipe = MessagePipe()
96 self.timer.timeout.get().append(self.sendOutPipe)
100 """Displays the ConversationWindow"""
101 # raise NotImplementedError("Subclasses must implement this method")
104 """Hides the ConversationWindow"""
105 # raise NotImplementedError("Subclasses must implement this method")
107 def sendText(self, text):
108 """Sends text to the person with whom the user is conversing.
109 @returntype: L{Deferred<twisted.internet.defer.Deferred>}
111 self.person.sendMessage(text, None)
112 self.pipe.add("%s" % text)
113 self.pipe.clearOutText()
114 # print"<%s> %s" % (self.nickname, text)
116 def sendOutPipe(self):
117 if len(str(self.pipe.getOutText())) > 0:
118 if (self.pipe.getOutText()=="/QUIT"):
119 print "/quit detected...."
120 self.pipe.clearOutText()
123 print "sending chat : %s" % str(self.pipe.getOutText())
124 self.sendText(str(self.pipe.getOutText()))
125 self.pipe.clearOutText()
127 def showMessage(self, text, metadata=None):
128 """Display a message sent from the person with whom she is conversing
133 self.pipe.add("<%s> %s" % (self.person.name, text))
134 # raise NotImplementedError("Subclasses must implement this method")
136 def contactChangedNick(self, person, newnick):
137 """Change a person's name.
139 @type person: L{Person<interfaces.IPerson>}
140 @type newnick: string
142 self.person.name = newnick
143 self.pipe.add("-!- %s is now known as %s" % (person.name, newnick))
144 # self.blist.updateBuddyWindow()
146 def serverMsg(self, message):
147 """Displays a serverMsg in the group conversation window
149 @type message: string
151 self.pipe.add("-!- %s " % (message))
152 # self.blist.updateBuddyWindow()
154 class GroupConversation:
155 """A conversation with a group of people."""
156 def __init__(self, group, chatui):
158 @type group: L{Group<interfaces.IGroup>}
160 @type chatui: L{ChatUI}
165 self.pipe = MessagePipe()
166 # self.blist=ChatWindow()
168 self.timer.timeout.get().append(self.sendOutPipe)
169 self.timer.start(100)
172 """Displays the GroupConversationWindow."""
173 # raise NotImplementedError("Subclasses must implement this method")
176 """Hides the GroupConversationWindow."""
177 # raise NotImplementedError("Subclasses must implement this method")
179 def sendText(self, text):
180 """Sends text to the group.
182 @returntype: L{Deferred<twisted.internet.defer.Deferred>}
184 self.group.sendGroupMessage(text, None)
185 self.pipe.add("%s" % text)
186 self.pipe.clearOutText()
187 # print "nach im sending nach sending : %s" % str(self.pipe.getOutText())
190 def sendOutPipe(self):
191 if len(str(self.pipe.getOutText())) > 0:
192 if (self.pipe.getOutText()=="/QUIT"):
193 print "/quit detected...."
194 self.pipe.clearOutText()
197 print "sending group chat : %s" % str(self.pipe.getOutText())
198 self.sendText(str(self.pipe.getOutText()))
199 self.pipe.clearOutText()
201 def showGroupMessage(self, sender, text, metadata=None):
202 """Displays to the user a message sent to this group from the given sender
203 @type sender: string (XXX: Not Person?)
207 self.pipe.add("<%s/%s> %s" % (sender, self.group.name, text))
209 def setGroupMembers(self, members):
210 """Sets the list of members in the group and displays it to the user
212 self.members = members
213 self.refreshMemberList()
215 def setTopic(self, topic, author):
216 """Displays the topic (from the server) for the group conversation window
219 @type author: string (XXX: Not Person?)
221 self.pipe.add("-!- %s set the topic of %s to: %s" % (author, self.group.name, topic))
222 # print "-!- %s set the topic of %s to: %s" % (author, self.group.name, topic)
224 def serverMsg(self, message):
225 """Displays a serverMsg in the group conversation window
227 @type message: string
229 self.pipe.add("-!- %s " % (message))
231 def memberJoined(self, member):
232 """Adds the given member to the list of members in the group conversation
233 and displays this to the user
235 @type member: string (XXX: Not Person?)
237 if not member in self.members:
238 self.members.append(member)
239 self.pipe.add("-!- %s joined %s" % (member, self.group.name))
240 self.refreshMemberList()
242 def memberChangedNick(self, oldnick, newnick):
243 """Changes the oldnick in the list of members to newnick and displays this
246 @type oldnick: string
247 @type newnick: string
249 if oldnick in self.members:
250 self.members.remove(oldnick)
251 self.members.append(newnick)
252 #self.chatui.contactChangedNick(oldnick, newnick)
253 self.pipe.add("-!- %s is now known as %s in %s" % (oldnick, newnick, self.group.name))
254 self.refreshMemberList()
256 def memberLeft(self, member):
257 """Deletes the given member from the list of members in the group
258 conversation and displays the change to the user
262 if member in self.members:
263 self.members.remove(member)
264 self.pipe.add("-!- %s left %s" % (member, self.group.name))
265 self.refreshMemberList()
268 def refreshMemberList(self):
269 self.pipe.clearBuddyList()
270 self.members.sort(lambda x,y: cmp(string.lower(x), string.lower(y)))
271 self.pipe.getCannelName(self.group.name)
272 for member in self.members:
273 self.pipe.buildBuddyList(str(member))
274 # print "Channel : #%s" % self.group.name
275 print "Buddylist of #%s : \n%s" % (self.group.name, self.pipe.showBuddyList())
276 # self.pipe.showBuddyList()
277 # self.pipe.updateBuddyWindow(self.pipe.showBuddyList())
278 self.pipe.updateBuddyWindow()
281 """A GUI chat client"""
283 self.conversations = {} # cache of all direct windows
284 self.groupConversations = {} # cache of all group windows
285 self.persons = {} # keys are (name, client)
286 self.groups = {} # cache of all groups
287 self.onlineClients = [] # list of message sources currently online
288 self.contactsList = ContactsList(self)
289 self.pipe = MessagePipe()
292 def registerAccountClient(self, client):
293 """Notifies user that an account has been signed on to.
295 @type client: L{Client<interfaces.IClient>}
296 @returns: client, so that I may be used in a callback chain
298 self.pipe.debug("signing onto %s" % client.accountName)
299 self.onlineClients.append(client)
300 self.contactsList.registerAccountClient(client)
302 self.pipe.debug(" --- %s ---" % self.helper)
303 self.pipe.add("signing onto %s" % client)
304 self.pipe.add("signing onto %s" % client.accountName)
307 def unregisterAccountClient(self, client):
308 """Notifies user that an account has been signed off or disconnected
310 @type client: L{Client<interfaces.IClient>}
312 self.pipe.debug("signing off from %s" % client.accountName)
313 self.onlineClients.remove(client)
314 self.contactsList.unregisterAccountClient(client)
317 """Notifies user that an account has been signed off or disconnected
319 @type client: L{Client<interfaces.IClient>}
321 self.pipe.debug(" --- %s ---" % self.helper)
322 self.pipe.debug("signing off from %s" % self.helper.accountName)
323 self.pipe.add("signing off %s" % helper)
324 self.pipe.add("signing off %s" % helper.accountName)
325 self.onlineClients.remove(helper)
326 self.contactsList.unregisterAccountClient(helper)
328 def getContactsList(self):
330 @returntype: L{ContactsList}
332 self.pipe.debug("contactlist = %s" % self.contactsList)
333 return self.contactsList
336 def getConversation(self, person, Class=Conversation, stayHidden=0):
337 """For the given person object, returns the conversation window
338 or creates and returns a new conversation window if one does not exist.
340 @type person: L{Person<interfaces.IPerson>}
341 @type Class: L{Conversation<interfaces.IConversation>} class
342 @type stayHidden: boolean
344 @returntype: L{Conversation<interfaces.IConversation>}
346 conv = self.conversations.get(person)
348 conv = Class(person, self)
349 self.conversations[person] = conv
356 def getGroupConversation(self,group,Class=GroupConversation,stayHidden=0):
357 """For the given group object, returns the group conversation window or
358 creates and returns a new group conversation window if it doesn't exist
360 @type group: L{Group<interfaces.IGroup>}
361 @type Class: L{Conversation<interfaces.IConversation>} class
362 @type stayHidden: boolean
364 @returntype: L{GroupConversation<interfaces.IGroupConversation>}
366 conv = self.groupConversations.get(group)
368 conv = Class(group, self)
369 self.groupConversations[group] = conv
374 # print "[dreamIRC] : " , conv
377 def getPerson(self, name, client):
378 """For the given name and account client, returns the instance of the
379 AbstractPerson subclass, or creates and returns a new AbstractPerson
380 subclass of the type Class
383 @type client: L{Client<interfaces.IClient>}
385 @returntype: L{Person<interfaces.IPerson>}
387 account = client.account
388 p = self.persons.get((name, account))
390 p = account.getPerson(name)
391 self.persons[name, account] = p
394 def getGroup(self, name, client):
395 """For the given name and account client, returns the instance of the
396 AbstractGroup subclass, or creates and returns a new AbstractGroup
397 subclass of the type Class
400 @type client: L{Client<interfaces.IClient>}
402 @returntype: L{Group<interfaces.IGroup>}
404 # I accept 'client' instead of 'account' in my signature for
405 # backwards compatibility. (Groups changed to be Account-oriented
406 # in CVS revision 1.8.)
407 account = client.account
408 g = self.groups.get((name, account))
410 g = account.getGroup(name)
411 self.groups[name, account] = g
412 # self.pipe.add("joined %s" % g)
415 def contactChangedNick(self, oldnick, newnick):
416 """For the given person, changes the person's name to newnick, and
417 tells the contact list and any conversation windows with that person
420 @type oldnick: string
421 @type newnick: string
423 if self.persons.has_key((person.name, person.account)):
424 conv = self.conversations.get(person)
426 conv.contactChangedNick(person, newnick)
428 self.contactsList.contactChangedNick(person, newnick)
430 del self.persons[person.name, person.account]
431 person.name = newnick
432 self.persons[person.name, person.account] = person
434 def sendOutPipe(self):
435 print "groupchat %s" % self.pipe.OutText
436 if len(self.pipe.OutText()) > 0:
437 self.sendText(self.pipe.OutText())
438 self.pipe.clearOutText()