comparison frontends/wix/contact_list.py @ 72:f271fff3a713

MUC implementation: first draft /!\ the experimental muc branche of wokkel must be used - bridge: new roomJoined signal - wix: contact list widget is now in a separate file, and manage different kinds of presentation - wix: chat window now manage group chat (first draft, not working yet) - wix: constants are now in a separate class, so then can be accessible from everywhere - wix: new menu to join room (do nothing yet, except entering in a test room) - new plugin for xep 0045 (MUC), use wokkel experimental MUC branch - plugins: the profile is now given for get_handler, cause it can be used internally by a plugin (e.g.: xep-0045 plugin)
author Goffi <goffi@goffi.org>
date Sun, 21 Mar 2010 10:28:55 +1100
parents
children 7322a41f8a8e
comparison
equal deleted inserted replaced
71:efe81b61673c 72:f271fff3a713
1 import wx
2 from quick_frontend.quick_contact_list import QuickContactList
3 from logging import debug, info, error
4 from cgi import escape
5 from tools.jid import JID
6
7
8 class Group(str):
9 """Class used to recognize groups"""
10
11 class Contact(str):
12 """Class used to recognize groups"""
13
14 class ContactList(wx.SimpleHtmlListBox, QuickContactList):
15 """Customized control to manage contacts."""
16
17 def __init__(self, parent, host, type="JID"):
18 """init the contact list
19 @param parent: WxWidgets parent of the widget
20 @param host: wix main app class
21 @param type: type of contact list: "JID" for the usual big jid contact list
22 "CUSTOM" for a customized contact list (self.__presentItem must then be overrided)
23 """
24 wx.SimpleHtmlListBox.__init__(self, parent, -1)
25 QuickContactList.__init__(self, host.CM)
26 self.host = host
27 self.type = type
28 self.__typeSwitch()
29 self.groups = {} #list contacts in each groups, key = group
30 self.Bind(wx.EVT_LISTBOX, self.onSelected)
31 self.Bind(wx.EVT_LISTBOX_DCLICK, self.onActivated)
32
33 def __typeSwitch(self):
34 if self.type == "JID":
35 self.__presentItem = self.__presentItemJID
36 elif type != "CUSTOM":
37 self.__presentItem = self.__presentItemDefault
38
39 def __find_idx(self, entity):
40 """Find indexes of given contact (or groups) in contact list, manage jid
41 @return: list of indexes"""
42 result=[]
43 for i in range(self.GetCount()):
44 if (type(entity) == JID and type(self.GetClientData(i)) == JID and self.GetClientData(i).short == entity.short) or\
45 self.GetClientData(i) == entity:
46 result.append(i)
47 return result
48
49 def replace(self, contact, groups=None):
50 debug(_("update %s") % contact)
51 if not self.__find_idx(contact):
52 self.add(contact, groups)
53 else:
54 for i in self.__find_idx(contact):
55 self.SetString(i, self.__presentItem(contact))
56
57 def disconnect(self, contact):
58 self.remove(contact) #for now, we only show online contacts
59
60 def __eraseGroup(self, group):
61 """Erase all contacts in group
62 @param group: group to erase
63 @return: True if something as been erased"""
64 erased = False
65 indexes = self.__find_idx(group)
66 for idx in indexes:
67 while idx<self.GetCount()-1 and type(self.GetClientData(idx+1)) != Group:
68 erased = True
69 self.Delete(idx+1)
70 return erased
71
72
73 def __presentGroup(self, group):
74 """Make a nice presentation for the contact groups"""
75 html = """-- [%s] --""" % group
76
77 return html
78
79 def __presentItemDefault(self, contact):
80 """Make a basic presentation of string contacts in the list."""
81 return contact
82
83 def __presentItemJID(self, jid):
84 """Make a nice presentation of the contact in the list for JID contacts."""
85 name = self.CM.getAttr(jid,'name')
86 nick = self.CM.getAttr(jid,'nick')
87 show = filter(lambda x:x[0]==self.CM.getAttr(jid,'show'), const_STATUS)[0]
88 #show[0]==shortcut
89 #show[1]==human readable
90 #show[2]==color (or None)
91 show_html = "<font color='%s'>[%s]</font>" % (show[2], show[1]) if show[2] else ""
92 status = self.CM.getAttr(jid,'status') or ''
93 avatar = self.CM.getAttr(jid,'avatar') or IMAGE_DIR+'/empty_avatar.png'
94
95 #XXX: yes table I know :) but wxHTML* doesn't support CSS
96 html = """
97 <table border='0'>
98 <td>
99 <img height='64' width='64' src='%s' />
100 </td>
101 <td>
102 <b>%s</b> %s<br />
103 <i>%s</i>
104 </td>
105 </table>
106 """ % (avatar,
107 escape(nick or name or jid.node or jid.short),
108 show_html,
109 escape(status))
110
111 return html
112
113 def clear_contacts(self):
114 """Clear all the contact list"""
115 self.Clear()
116
117 def add(self, contact, groups = None):
118 """add a contact to the list"""
119 debug (_("adding %s"),contact)
120 #gof: groups = param_groups or self.CM.getAttr(jid, 'groups')
121 if not groups:
122 idx = self.Insert(self.__presentItem(contact), 0, contact)
123 else:
124 for group in groups:
125 indexes = self.__find_idx(group)
126 gp_idx = 0
127 if not indexes: #this is a new group, we have to create it
128 gp_idx = self.Append(self.__presentGroup(group), Group(group))
129 else:
130 gp_idx = indexes[0]
131
132 self.Insert(self.__presentItem(contact), gp_idx+1, contact)
133
134
135
136 def remove(self, contact):
137 """remove a contact from the list"""
138 debug (_("removing %s"), contact)
139 list_idx = self.__find_idx(contact)
140 list_idx.reverse() #we me make some deletions, we have to reverse the order
141 for i in list_idx:
142 self.Delete(i)
143
144 def onSelected(self, event):
145 """Called when a contact is selected."""
146 data = self.getSelection()
147 if data == None: #we have a group
148 group = self.GetClientData(self.GetSelection())
149 erased = self.__eraseGroup(group)
150 if not erased: #the group was already erased, we can add again the contacts
151 contacts = self.CM.getContFromGroup(group)
152 contacts.sort()
153 id_insert = self.GetSelection()+1
154 for contact in contacts:
155 self.Insert(self.__presentItem(contact), id_insert, contact)
156 self.SetSelection(wx.NOT_FOUND)
157 event.Skip(False)
158 else:
159 event.Skip()
160
161 def onActivated(self, event):
162 """Called when a contact is clicked or activated with keyboard."""
163 data = self.getSelection()
164 self.onActivatedCB(data)
165 event.Skip()
166
167 def getSelection(self):
168 """Return the selected contact, or an empty string if there is not"""
169 if self.GetSelection() == wx.NOT_FOUND:
170 return None
171 data = self.GetClientData(self.GetSelection())
172 if type(data) == Group:
173 return None
174 return data
175
176 def registerActivatedCB(self, cb):
177 """Register a callback with manage contact activation."""
178 self.onActivatedCB=cb
179