# Twisted, the Framework of Your Internet # Copyright (C) 2001-2002 Matthew W. Lefkowitz # # This library is free software; you can redistribute it and/or # modify it under the terms of version 2.1 of the GNU Lesser General Public # License as published by the Free Software Foundation. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # from twisted.im.locals import OFFLINE, ONLINE, AWAY class ContactsList: """A GUI object that displays a contacts list""" def __init__(self, chatui): """ @param chatui: ??? @type chatui: L{ChatUI} """ self.chatui = chatui self.contacts = {} self.onlineContacts = {} self.clients = [] def setContactStatus(self, person): """Inform the user that a person's status has changed. @type person: L{Person} """ if not self.contacts.has_key(person.name): self.contacts[person.name] = person if not self.onlineContacts.has_key(person.name) and \ (person.status == ONLINE or person.status == AWAY): self.onlineContacts[person.name] = person if self.onlineContacts.has_key(person.name) and \ person.status == OFFLINE: del self.onlineContacts[person.name] def registerAccountClient(self, client): """Notify the user that an account client has been signed on to. @type client: L{Client} """ if not client in self.clients: self.clients.append(client) def unregisterAccountClient(self, client): """Notify the user that an account client has been signed off or disconnected from. @type client: L{Client} """ if client in self.clients: self.clients.remove(client) def contactChangedNick(self, person, newnick): oldname = person.name if self.contacts.has_key(oldname): del self.contacts[oldname] person.name = newnick self.contacts[newnick] = person if self.onlineContacts.has_key(oldname): del self.onlineContacts[oldname] self.onlineContacts[newnick] = person class Conversation: """A GUI window of a conversation with a specific person""" def __init__(self, person, chatui): """ @type person: L{Person} @type chatui: L{ChatUI} """ self.chatui = chatui self.person = person def show(self): """Displays the ConversationWindow""" raise NotImplementedError("Subclasses must implement this method") def hide(self): """Hides the ConversationWindow""" raise NotImplementedError("Subclasses must implement this method") def sendText(self, text): """Sends text to the person with whom the user is conversing. @returntype: L{Deferred} """ self.person.sendMessage(text, None) def showMessage(self, text, metadata=None): """Display a message sent from the person with whom she is conversing @type text: string @type metadata: dict """ raise NotImplementedError("Subclasses must implement this method") def contactChangedNick(self, person, newnick): """Change a person's name. @type person: L{Person} @type newnick: string """ self.person.name = newnick class GroupConversation: """A conversation with a group of people.""" def __init__(self, group, chatui): """ @type group: L{Group} @param chatui: ??? @type chatui: L{ChatUI} """ self.chatui = chatui self.group = group self.members = [] def show(self): """Displays the GroupConversationWindow.""" raise NotImplementedError("Subclasses must implement this method") def hide(self): """Hides the GroupConversationWindow.""" raise NotImplementedError("Subclasses must implement this method") def sendText(self, text): """Sends text to the group. @type text: string @returntype: L{Deferred} """ self.group.sendGroupMessage(text, None) def showGroupMessage(self, sender, text, metadata=None): """Displays to the user a message sent to this group from the given sender @type sender: string (XXX: Not Person?) @type text: string @type metadata: dict """ raise NotImplementedError("Subclasses must implement this method") def setGroupMembers(self, members): """Sets the list of members in the group and displays it to the user """ self.members = members def setTopic(self, topic, author): """Displays the topic (from the server) for the group conversation window @type topic: string @type author: string (XXX: Not Person?) """ raise NotImplementedError("Subclasses must implement this method") def memberJoined(self, member): """Adds the given member to the list of members in the group conversation and displays this to the user @type member: string (XXX: Not Person?) """ if not member in self.members: self.members.append(member) def memberChangedNick(self, oldnick, newnick): """Changes the oldnick in the list of members to newnick and displays this change to the user @type oldnick: string @type newnick: string """ if oldnick in self.members: self.members.remove(oldnick) self.members.append(newnick) #self.chatui.contactChangedNick(oldnick, newnick) def memberLeft(self, member): """Deletes the given member from the list of members in the group conversation and displays the change to the user @type member: string """ if member in self.members: self.members.remove(member) class ChatUI: """A GUI chat client""" def __init__(self): self.conversations = {} # cache of all direct windows self.groupConversations = {} # cache of all group windows self.persons = {} # keys are (name, client) self.groups = {} # cache of all groups self.onlineClients = [] # list of message sources currently online self.contactsList = ContactsList(self) def registerAccountClient(self, client): """Notifies user that an account has been signed on to. @type client: L{Client} """ print "signing onto", client.accountName self.onlineClients.append(client) self.contactsList.registerAccountClient(client) def unregisterAccountClient(self, client): """Notifies user that an account has been signed off or disconnected @type client: L{Client} """ print "signing off from", client.accountName self.onlineClients.remove(client) self.contactsList.unregisterAccountClient(client) def getContactsList(self): """ @returntype: L{ContactsList} """ return self.contactsList def getConversation(self, person, Class=Conversation, stayHidden=0): """For the given person object, returns the conversation window or creates and returns a new conversation window if one does not exist. @type person: L{Person} @type Class: L{Conversation} class @type stayHidden: boolean @returntype: L{Conversation} """ conv = self.conversations.get(person) if not conv: conv = Class(person, self) self.conversations[person] = conv if stayHidden: conv.hide() else: conv.show() return conv def getGroupConversation(self,group,Class=GroupConversation,stayHidden=0): """For the given group object, returns the group conversation window or creates and returns a new group conversation window if it doesn't exist @type group: L{Group} @type Class: L{Conversation} class @type stayHidden: boolean @returntype: L{GroupConversation} """ conv = self.groupConversations.get(group) if not conv: conv = Class(group, self) self.groupConversations[group] = conv if stayHidden: conv.hide() else: conv.show() return conv def getPerson(self, name, client, Class): """For the given name and account client, returns the instance of the AbstractPerson subclass, or creates and returns a new AbstractPerson subclass of the type Class @type name: string @type client: L{Client} @type Class: L{Person} class @returntype: L{Person} """ p = self.persons.get((name, client)) if not p: p = Class(name, client, self) self.persons[name, client] = p return p def getGroup(self, name, client, Class): """For the given name and account client, returns the instance of the AbstractGroup subclass, or creates and returns a new AbstractGroup subclass of the type Class @type name: string @type client: L{Client} @type Class: L{Group} class @returntype: L{Group} """ g = self.groups.get((name, client)) if not g: g = Class(name, client, self) self.groups[name, client] = g return g def contactChangedNick(self, oldnick, newnick): """For the given person, changes the person's name to newnick, and tells the contact list and any conversation windows with that person to change as well. @type oldnick: string @type newnick: string """ if self.persons.has_key((person.name, person.client)): conv = self.conversations.get(person) if conv: conv.contactChangedNick(person, newnick) self.contactsList.contactChangedNick(person, newnick) del self.persons[person.name, person.client] person.name = newnick self.persons[person.name, person.client] = person