view frontends/wix/contact_list.py @ 125:8d611eb9ae48

primitivus: contact list enhancement - primitivus: contact list now display groups and sexy name (instead of bare jid) - primitivus: contact list now show an alert when somebody want to contact you, and its chat window is not on the screen - primitivus: cursor is now visible when going to chat window (useful to go back in logs)
author Goffi <goffi@goffi.org>
date Mon, 12 Jul 2010 17:50:00 +0800
parents 961e0898271f
children 2f8c86488b05
line wrap: on
line source

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 __contains__(self, jid):
        return bool(self.__find_idx(jid))

    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'
        
        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()  #as we 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