| 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 |