diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/frontends/wix/contact_list.py	Sun Mar 21 10:28:55 2010 +1100
@@ -0,0 +1,179 @@
+import wx
+from quick_frontend.quick_contact_list import QuickContactList
+from logging import debug, info, error
+from cgi import escape
+from tools.jid  import JID
+
+
+class Group(str):
+    """Class used to recognize groups"""
+
+class Contact(str):
+    """Class used to recognize groups"""
+
+class ContactList(wx.SimpleHtmlListBox, QuickContactList):
+    """Customized control to manage contacts."""
+
+    def __init__(self, parent, host, type="JID"):
+        """init the contact list
+        @param parent: WxWidgets parent of the widget
+        @param host: wix main app class
+        @param type: type of contact list: "JID" for the usual big jid contact list
+                                           "CUSTOM" for a customized contact list (self.__presentItem must then be overrided)
+        """
+        wx.SimpleHtmlListBox.__init__(self, parent, -1)
+        QuickContactList.__init__(self, host.CM)
+        self.host = host
+        self.type = type
+        self.__typeSwitch()
+        self.groups = {}  #list contacts in each groups, key = group
+        self.Bind(wx.EVT_LISTBOX, self.onSelected)
+        self.Bind(wx.EVT_LISTBOX_DCLICK, self.onActivated)
+
+    def __typeSwitch(self):
+        if self.type == "JID":
+            self.__presentItem = self.__presentItemJID
+        elif type != "CUSTOM":
+            self.__presentItem = self.__presentItemDefault
+
+    def __find_idx(self, entity):
+        """Find indexes of given contact (or groups) in contact list, manage jid
+        @return: list of indexes"""
+        result=[]
+        for i in range(self.GetCount()):
+            if (type(entity) == JID and type(self.GetClientData(i)) == JID and self.GetClientData(i).short == entity.short) or\
+                self.GetClientData(i) == entity:
+                result.append(i)
+        return result
+
+    def replace(self, contact, groups=None):
+        debug(_("update %s") % contact)
+        if not self.__find_idx(contact):
+            self.add(contact, groups)
+        else:
+            for i in self.__find_idx(contact):
+                self.SetString(i, self.__presentItem(contact))
+
+    def disconnect(self, contact):
+        self.remove(contact) #for now, we only show online contacts
+    
+    def __eraseGroup(self, group):
+        """Erase all contacts in group
+        @param group: group to erase
+        @return: True if something as been erased"""
+        erased = False
+        indexes = self.__find_idx(group)
+        for idx in indexes:
+            while idx<self.GetCount()-1 and type(self.GetClientData(idx+1)) != Group:
+                erased = True
+                self.Delete(idx+1)
+        return erased
+
+
+    def __presentGroup(self, group):
+        """Make a nice presentation for the contact groups"""
+        html = """-- [%s] --""" % group
+
+        return html
+
+    def __presentItemDefault(self, contact):
+        """Make a basic presentation of string contacts in the list."""
+        return contact
+    
+    def __presentItemJID(self, jid):
+        """Make a nice presentation of the contact in the list for JID contacts."""
+        name = self.CM.getAttr(jid,'name')
+        nick = self.CM.getAttr(jid,'nick')
+        show =  filter(lambda x:x[0]==self.CM.getAttr(jid,'show'), const_STATUS)[0]
+        #show[0]==shortcut
+        #show[1]==human readable
+        #show[2]==color (or None)
+        show_html = "<font color='%s'>[%s]</font>" % (show[2], show[1]) if show[2] else ""
+        status = self.CM.getAttr(jid,'status') or ''
+        avatar = self.CM.getAttr(jid,'avatar') or IMAGE_DIR+'/empty_avatar.png'
+        
+        #XXX: yes table I know :) but wxHTML* doesn't support CSS
+        html = """
+        <table border='0'>
+        <td>
+            <img  height='64' width='64' src='%s' />
+        </td>
+        <td>
+            <b>%s</b> %s<br />
+            <i>%s</i>
+        </td>
+        </table>
+        """ % (avatar,
+               escape(nick or name or jid.node or jid.short),
+               show_html,
+               escape(status)) 
+
+        return html
+
+    def clear_contacts(self):
+        """Clear all the contact list"""
+        self.Clear()
+
+    def add(self, contact, groups = None):
+        """add a contact to the list"""
+        debug (_("adding %s"),contact)
+        #gof: groups = param_groups or self.CM.getAttr(jid, 'groups')
+        if not groups:
+            idx = self.Insert(self.__presentItem(contact), 0, contact)
+        else:
+            for group in groups:
+                indexes = self.__find_idx(group)
+                gp_idx = 0
+                if not indexes:  #this is a new group, we have to create it
+                    gp_idx = self.Append(self.__presentGroup(group), Group(group))
+                else:
+                    gp_idx = indexes[0]
+
+                self.Insert(self.__presentItem(contact), gp_idx+1, contact)
+
+
+
+    def remove(self, contact):
+        """remove a contact from the list"""
+        debug (_("removing %s"), contact)
+        list_idx = self.__find_idx(contact)
+        list_idx.reverse()  #we me make some deletions, we have to reverse the order
+        for i in list_idx:
+            self.Delete(i)
+
+    def onSelected(self, event):
+        """Called when a contact is selected."""
+        data = self.getSelection()
+        if data == None: #we have a group
+            group = self.GetClientData(self.GetSelection())
+            erased = self.__eraseGroup(group)
+            if not erased: #the group was already erased, we can add again the contacts
+                contacts = self.CM.getContFromGroup(group)
+                contacts.sort()
+                id_insert = self.GetSelection()+1
+                for contact in contacts:
+                    self.Insert(self.__presentItem(contact), id_insert, contact)
+            self.SetSelection(wx.NOT_FOUND)
+            event.Skip(False)
+        else:
+            event.Skip()
+    
+    def onActivated(self, event):
+        """Called when a contact is clicked or activated with keyboard."""
+        data = self.getSelection()
+        self.onActivatedCB(data)
+        event.Skip()
+
+    def getSelection(self):
+        """Return the selected contact, or an empty string if there is not"""
+        if self.GetSelection() == wx.NOT_FOUND:
+            return None
+        data = self.GetClientData(self.GetSelection())
+        if type(data) == Group:
+            return None
+        return data
+
+    def registerActivatedCB(self, cb):
+        """Register a callback with manage contact activation."""
+        self.onActivatedCB=cb
+