| Viewing file:  basechat.py (16.09 KB)      -rw-r--r-- Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
# -*- test-case-name: twisted.words.test.test_basechat -*-# Copyright (c) Twisted Matrix Laboratories.
 # See LICENSE for details.
 
 """
 Base classes for Instance Messenger clients.
 """
 
 from twisted.words.im.locals import OFFLINE, ONLINE, AWAY
 
 
 class ContactsList:
 """
 A GUI object that displays a contacts list.
 
 @ivar chatui: The GUI chat client associated with this contacts list.
 @type chatui: L{ChatUI}
 
 @ivar contacts: The contacts.
 @type contacts: C{dict} mapping C{str} to a L{IPerson<interfaces.IPerson>}
 provider
 
 @ivar onlineContacts: The contacts who are currently online (have a status
 that is not C{OFFLINE}).
 @type onlineContacts: C{dict} mapping C{str} to a
 L{IPerson<interfaces.IPerson>} provider
 
 @ivar clients: The signed-on clients.
 @type clients: C{list} of L{IClient<interfaces.IClient>} providers
 """
 def __init__(self, chatui):
 """
 @param chatui: The GUI chat client associated with this contacts list.
 @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.
 
 @param person: The person whose status has changed.
 @type person: L{IPerson<interfaces.IPerson>} provider
 """
 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.
 
 @param client: The client being added to your list of account clients.
 @type client: L{IClient<interfaces.IClient>} provider
 """
 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.
 
 @param client: The client being removed from the list of account
 clients.
 @type client: L{IClient<interfaces.IClient>} provider
 """
 if client in self.clients:
 self.clients.remove(client)
 
 
 def contactChangedNick(self, person, newnick):
 """
 Update your contact information to reflect a change to a contact's
 nickname.
 
 @param person: The person in your contacts list whose nickname is
 changing.
 @type person: L{IPerson<interfaces.IPerson>} provider
 
 @param newnick: The new nickname for this person.
 @type newnick: C{str}
 """
 oldname = person.name
 if oldname in self.contacts:
 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.
 
 @ivar person: The person who you're having this conversation with.
 @type person: L{IPerson<interfaces.IPerson>} provider
 
 @ivar chatui: The GUI chat client associated with this conversation.
 @type chatui: L{ChatUI}
 """
 def __init__(self, person, chatui):
 """
 @param person: The person who you're having this conversation with.
 @type person: L{IPerson<interfaces.IPerson>} provider
 
 @param chatui: The GUI chat client associated with this conversation.
 @type chatui: L{ChatUI}
 """
 self.chatui = chatui
 self.person = person
 
 
 def show(self):
 """
 Display the ConversationWindow.
 """
 raise NotImplementedError("Subclasses must implement this method")
 
 
 def hide(self):
 """
 Hide the ConversationWindow.
 """
 raise NotImplementedError("Subclasses must implement this method")
 
 
 def sendText(self, text):
 """
 Send text to the person with whom the user is conversing.
 
 @param text: The text to be sent.
 @type text: C{str}
 """
 self.person.sendMessage(text, None)
 
 
 def showMessage(self, text, metadata=None):
 """
 Display a message sent from the person with whom the user is conversing.
 
 @param text: The sent message.
 @type text: C{str}
 
 @param metadata: Metadata associated with this message.
 @type metadata: C{dict}
 """
 raise NotImplementedError("Subclasses must implement this method")
 
 
 def contactChangedNick(self, person, newnick):
 """
 Change a person's name.
 
 @param person: The person whose nickname is changing.
 @type person: L{IPerson<interfaces.IPerson>} provider
 
 @param newnick: The new nickname for this person.
 @type newnick: C{str}
 """
 self.person.name = newnick
 
 
 
 class GroupConversation:
 """
 A GUI window of a conversation with a group of people.
 
 @ivar chatui: The GUI chat client associated with this conversation.
 @type chatui: L{ChatUI}
 
 @ivar group: The group of people that are having this conversation.
 @type group: L{IGroup<interfaces.IGroup>} provider
 
 @ivar members: The names of the people in this conversation.
 @type members: C{list} of C{str}
 """
 def __init__(self, group, chatui):
 """
 @param chatui: The GUI chat client associated with this conversation.
 @type chatui: L{ChatUI}
 
 @param group: The group of people that are having this conversation.
 @type group: L{IGroup<interfaces.IGroup>} provider
 """
 self.chatui = chatui
 self.group = group
 self.members = []
 
 
 def show(self):
 """
 Display the GroupConversationWindow.
 """
 raise NotImplementedError("Subclasses must implement this method")
 
 
 def hide(self):
 """
 Hide the GroupConversationWindow.
 """
 raise NotImplementedError("Subclasses must implement this method")
 
 
 def sendText(self, text):
 """
 Send text to the group.
 
 @param: The text to be sent.
 @type text: C{str}
 """
 self.group.sendGroupMessage(text, None)
 
 
 def showGroupMessage(self, sender, text, metadata=None):
 """
 Display to the user a message sent to this group from the given sender.
 
 @param sender: The person sending the message.
 @type sender: C{str}
 
 @param text: The sent message.
 @type text: C{str}
 
 @param metadata: Metadata associated with this message.
 @type metadata: C{dict}
 """
 raise NotImplementedError("Subclasses must implement this method")
 
 
 def setGroupMembers(self, members):
 """
 Set the list of members in the group.
 
 @param members: The names of the people that will be in this group.
 @type members: C{list} of C{str}
 """
 self.members = members
 
 
 def setTopic(self, topic, author):
 """
 Change the topic for the group conversation window and display this
 change to the user.
 
 @param topic: This group's topic.
 @type topic: C{str}
 
 @param author: The person changing the topic.
 @type author: C{str}
 """
 raise NotImplementedError("Subclasses must implement this method")
 
 
 def memberJoined(self, member):
 """
 Add the given member to the list of members in the group conversation
 and displays this to the user.
 
 @param member: The person joining the group conversation.
 @type member: C{str}
 """
 if not member in self.members:
 self.members.append(member)
 
 
 def memberChangedNick(self, oldnick, newnick):
 """
 Change the nickname for a member of the group conversation and displays
 this change to the user.
 
 @param oldnick: The old nickname.
 @type oldnick: C{str}
 
 @param newnick: The new nickname.
 @type newnick: C{str}
 """
 if oldnick in self.members:
 self.members.remove(oldnick)
 self.members.append(newnick)
 
 
 def memberLeft(self, member):
 """
 Delete the given member from the list of members in the group
 conversation and displays the change to the user.
 
 @param member: The person leaving the group conversation.
 @type member: C{str}
 """
 if member in self.members:
 self.members.remove(member)
 
 
 
 class ChatUI:
 """
 A GUI chat client.
 
 @type conversations: C{dict} of L{Conversation}
 @ivar conversations: A cache of all the direct windows.
 
 @type groupConversations: C{dict} of L{GroupConversation}
 @ivar groupConversations: A cache of all the group windows.
 
 @type persons: C{dict} with keys that are a C{tuple} of (C{str},
 L{IAccount<interfaces.IAccount>} provider) and values that are
 L{IPerson<interfaces.IPerson>} provider
 @ivar persons: A cache of all the users associated with this client.
 
 @type groups: C{dict} with keys that are a C{tuple} of (C{str},
 L{IAccount<interfaces.IAccount>} provider) and values that are
 L{IGroup<interfaces.IGroup>} provider
 @ivar groups: A cache of all the groups associated with this client.
 
 @type onlineClients: C{list} of L{IClient<interfaces.IClient>} providers
 @ivar onlineClients: A list of message sources currently online.
 
 @type contactsList: L{ContactsList}
 @ivar contactsList: A contacts list.
 """
 def __init__(self):
 self.conversations = {}
 self.groupConversations = {}
 self.persons = {}
 self.groups = {}
 self.onlineClients = []
 self.contactsList = ContactsList(self)
 
 
 def registerAccountClient(self, client):
 """
 Notify the user that an account has been signed on to.
 
 @type client: L{IClient<interfaces.IClient>} provider
 @param client: The client account for the person who has just signed on.
 
 @rtype client: L{IClient<interfaces.IClient>} provider
 @return: The client, so that it may be used in a callback chain.
 """
 self.onlineClients.append(client)
 self.contactsList.registerAccountClient(client)
 return client
 
 
 def unregisterAccountClient(self, client):
 """
 Notify the user that an account has been signed off or disconnected.
 
 @type client: L{IClient<interfaces.IClient>} provider
 @param client: The client account for the person who has just signed
 off.
 """
 self.onlineClients.remove(client)
 self.contactsList.unregisterAccountClient(client)
 
 
 def getContactsList(self):
 """
 Get the contacts list associated with this chat window.
 
 @rtype: L{ContactsList}
 @return: The contacts list associated with this chat window.
 """
 return self.contactsList
 
 
 def getConversation(self, person, Class=Conversation, stayHidden=False):
 """
 For the given person object, return the conversation window or create
 and return a new conversation window if one does not exist.
 
 @type person: L{IPerson<interfaces.IPerson>} provider
 @param person: The person whose conversation window we want to get.
 
 @type Class: L{IConversation<interfaces.IConversation>} implementor
 @param: The kind of conversation window we want. If the conversation
 window for this person didn't already exist, create one of this type.
 
 @type stayHidden: C{bool}
 @param stayHidden: Whether or not the conversation window should stay
 hidden.
 
 @rtype: L{IConversation<interfaces.IConversation>} provider
 @return: The conversation window.
 """
 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=False):
 """
 For the given group object, return the group conversation window or
 create and return a new group conversation window if it doesn't exist.
 
 @type group: L{IGroup<interfaces.IGroup>} provider
 @param group: The group whose conversation window we want to get.
 
 @type Class: L{IConversation<interfaces.IConversation>} implementor
 @param: The kind of conversation window we want. If the conversation
 window for this person didn't already exist, create one of this type.
 
 @type stayHidden: C{bool}
 @param stayHidden: Whether or not the conversation window should stay
 hidden.
 
 @rtype: L{IGroupConversation<interfaces.IGroupConversation>} provider
 @return: The group conversation window.
 """
 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):
 """
 For the given name and account client, return an instance of a
 L{IGroup<interfaces.IPerson>} provider or create and return a new
 instance of a L{IGroup<interfaces.IPerson>} provider.
 
 @type name: C{str}
 @param name: The name of the person of interest.
 
 @type client: L{IClient<interfaces.IClient>} provider
 @param client: The client account of interest.
 
 @rtype: L{IPerson<interfaces.IPerson>} provider
 @return: The person with that C{name}.
 """
 account = client.account
 p = self.persons.get((name, account))
 if not p:
 p = account.getPerson(name)
 self.persons[name, account] = p
 return p
 
 
 def getGroup(self, name, client):
 """
 For the given name and account client, return an instance of a
 L{IGroup<interfaces.IGroup>} provider or create and return a new instance
 of a L{IGroup<interfaces.IGroup>} provider.
 
 @type name: C{str}
 @param name: The name of the group of interest.
 
 @type client: L{IClient<interfaces.IClient>} provider
 @param client: The client account of interest.
 
 @rtype: L{IGroup<interfaces.IGroup>} provider
 @return: The group with that C{name}.
 """
 # I accept 'client' instead of 'account' in my signature for
 # backwards compatibility.  (Groups changed to be Account-oriented
 # in CVS revision 1.8.)
 account = client.account
 g = self.groups.get((name, account))
 if not g:
 g = account.getGroup(name)
 self.groups[name, account] = g
 return g
 
 
 def contactChangedNick(self, person, newnick):
 """
 For the given C{person}, change the C{person}'s C{name} to C{newnick}
 and tell the contact list and any conversation windows with that
 C{person} to change as well.
 
 @type person: L{IPerson<interfaces.IPerson>} provider
 @param person: The person whose nickname will get changed.
 
 @type newnick: C{str}
 @param newnick: The new C{name} C{person} will take.
 """
 oldnick = person.name
 if (oldnick, person.account) in self.persons:
 conv = self.conversations.get(person)
 if conv:
 conv.contactChangedNick(person, newnick)
 self.contactsList.contactChangedNick(person, newnick)
 del self.persons[oldnick, person.account]
 person.name = newnick
 self.persons[person.name, person.account] = person
 
 |