# -*- coding: utf-8 -*-
# This file is part of emesene.
#
# Emesene is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# emesene is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with emesene; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
'''a gtk implementation of abstract.ContactList'''
import gtk
import gobject
import abstract.ContactList
import abstract.status as status
from abstract.GroupManager import Group
from abstract.ContactManager import Contact
class ContactList(abstract.ContactList.ContactList, gtk.TreeView):
'''a gtk implementation of abstract.ContactList'''
def __init__(self, contacts, groups, dialog):
'''class constructor'''
abstract.ContactList.ContactList.__init__(self, contacts, groups,
dialog)
gtk.TreeView.__init__(self)
# the image (None for groups) the object (group or contact) and
# the string to display
self._model = gtk.TreeStore(gtk.gdk.Pixbuf, object, str)
self.model = self._model.filter_new(root=None)
self.model.set_visible_func(self._visible_func)
self._model.set_sort_func(1, self._sort_method)
self._model.set_sort_column_id(1, gtk.SORT_ASCENDING)
self.set_model(self.model)
crt = gtk.CellRendererText()
column = gtk.TreeViewColumn()
column.set_expand(True)
exp_column = gtk.TreeViewColumn()
exp_column.set_max_width(16)
self.append_column(exp_column)
self.append_column(column)
self.set_expander_column(exp_column)
column.pack_start(crt)
column.add_attribute(crt, 'markup', 2)
self.set_search_column(2)
self.set_headers_visible(False)
self.connect('row-activated', self._on_row_activated)
self.connect('button-press-event' , self._on_button_press_event)
# valid values:
# + NICK
# + ACCOUNT
# + DISPLAY_NAME (alias if available, or nick if available or mail)
# + STATUS
# + MESSAGE
self.nick_template = '%DISPLAY_NAME%\n'
self.nick_template += '<span foreground="#AAAAAA" size="small">'
self.nick_template += '%ACCOUNT%\n(%STATUS%) - %MESSAGE%</span>'
# valid values:
# + NAME
# + ONLINE_COUNT
# + TOTAL_COUNT
self.group_template = '<b>%NAME% (%ONLINE_COUNT%/%TOTAL_COUNT%)</b>'
def _visible_func(self, model, _iter):
'''return True if the row should be displayed according to the
value of the config'''
obj = self._model[_iter][1]
if not obj:
return
if type(obj) == Group:
if not self.show_empty_groups:
# get a list of contact objects from a list of accounts
contacts = self.contacts.get_contacts(obj.contacts)
if self.contacts.get_online_total_count(contacts)[0] == 0:
return False
return True
# i think joining all the text from a user with a new line between
# and searching on one string is faster (and the user cant add
# a new line to the entry so..)
if self._filter_text:
if '\n'.join((obj.account, obj.alias, obj.nick, obj.message,
obj.account)).lower().find(self._filter_text) == -1:
return False
else:
return True
if not self.show_offline and obj.status == status.OFFLINE:
return False
return True
def _sort_method(self, model, iter1, iter2, user_data=None):
'''callback called to decide the order of the contacts'''
obj1 = self._model[iter1][1]
obj2 = self._model[iter2][1]
if type(obj1) == Group and type(obj2) == Group:
return self.compare_groups(obj1, obj2)
elif type(obj1) == Contact and type(obj2) == Contact:
return self.compare_contacts(obj1, obj2)
elif type(obj1) == Group and type(obj2) == Contact:
return -1
else:
return 1
def _get_selected(self):
'''return the selected row or None'''
return self.model.convert_iter_to_child_iter(\
self.get_selection().get_selected()[1])
def _on_row_activated(self, treeview, path, view_column):
'''callback called when the user selects a row'''
group = self.get_group_selected()
contact = self.get_contact_selected()
if group:
self.signal_emit('group-selected', group)
elif contact:
self.signal_emit('contact-selected', contact)
else:
print 'nothing selected?'
def _on_button_press_event(self, treeview, event):
'''callback called when the user press a button over a row
chek if it's the roght button and emit a signal on that case'''
if event.button == 3:
paths = self.get_path_at_pos(int(event.x), int(event.y))
if paths is None:
print 'invalid path'
elif len(paths) > 0:
iterator = self.model.get_iter(paths[0])
child_iter = self.model.convert_iter_to_child_iter(iterator)
obj = self._model[child_iter][1]
if type(obj) == Group:
self.signal_emit('group-menu-selected', obj)
elif type(obj) == Contact:
self.signal_emit('contact-menu-selected', obj)
else:
print 'empty paths?'
# overrided methods
def refilter(self):
'''refilter the values according to the value of self.filter_text'''
self.model.refilter()
def is_group_selected(self):
'''return True if a group is selected'''
return type(self._model[self._get_selected()][1]) == Group
def is_contact_selected(self):
'''return True if a contact is selected'''
return type(self._model[self._get_selected()][1]) == Contact
def get_group_selected(self):
'''return a group object if there is a group selected, None otherwise
'''
if self.is_group_selected():
return self._model[self._get_selected()][1]
return None
def get_contact_selected(self):
'''return a contact object if there is a group selected, None otherwise
'''
if self.is_contact_selected():
return self._model[self._get_selected()][1]
return None
def add_group(self, group):
'''add a group to the contact list'''
if self.order_by_status:
return None
group_data = (None, group, self.format_group(group))
for row in self._model:
obj = row[1]
if type(obj) == Group:
if obj.name == group.name:
print 'Trying to add an existing group!', obj.name
return row.iter
return self._model.append(None, group_data)
def remove_group(self, group):
'''remove a group from the contact list'''
for row in self._model:
obj = row[1]
if type(obj) == Group and obj.name == group.name:
del self._model[row.iter]
def add_contact(self, contact, group=None):
'''add a contact to the contact list, add it to the group if
group is not None'''
contact_data = (None, contact, self.format_nick(contact))
# if no group add it to the root, but check that it's not on a group
# or in the root already
if not group or self.order_by_status:
for row in self._model:
obj = row[1]
# check on group
if type(obj) == Group:
for contact_row in row.iterchildren():
con = contact_row[1]
if con.account == contact.account:
return contact_row.iter
# check on the root
elif type(obj) == Contact and obj.account == contact.account:
return row.iter
return self._model.append(None, contact_data)
for row in self._model:
obj = row[1]
if type(obj) == Group and obj.name == group.name:
return_iter = self._model.append(row.iter, contact_data)
self.update_group(group)
# search the use on the root to remove it if it's there
# since we added him to a group
for irow in self._model:
iobj = irow[1]
if type(iobj) == Contact and \
iobj.account == contact.account:
del self._model[irow.iter]
return return_iter
else:
self.add_group(group)
return self.add_contact(contact, group)
def remove_contact(self, contact, group=None):
'''remove a contact from thespecifiedgroupgroupNone import
then remove him from allgroups import
if not group:
# go though the groups and the contacts without group
for row in self._model:
obj = row[1]
# if we get a group we go through the contacts
if type(obj) == Group:
for contact_row in row.iterchildren():
con = contact_row[1]
# if we find it, we remove it
if con.account == contact.account:
del self._model[contact_row.iter]
self.update_group(obj)
# if it's a contact without group (at the root)
elif type(obj) == Contact and obj.account == contact.account:
del self._model[row.iter]
return
# go though the groups
for row in self._model:
obj = row[1]
# if it's the group we are searching
if type(obj) == Group and obj.name == group.name:
# go through all the contacts
for contact_row in row.iterchildren():
con = contact_row[1]
# if we find it, we remove it
if con.account == contact.account:
del self._model[contact_row.iter]
self.update_group(group)
def clear(self):
'''clear the contact list'''
self._model.clear()
def update_contact(self, contact):
'''update the data of contact'''
contact_data = (None, contact, self.format_nick(contact))
for row in self._model:
obj = row[1]
if type(obj) == Group:
for contact_row in row.iterchildren():
con = contact_row[1]
if con.account == contact.account:
self._model[contact_row.iter] = contact_data
self.update_group(obj)
elif type(obj) == Contact and obj.account == contact.account:
self._model[row.iter] = contact_data
def update_group(self, group):
'''update the data of group'''
group_data = (None, group, self.format_group(group))
for row in self._model:
obj = row[1]
if type(obj) == Group and obj.name == group.name:
self._model[row.iter] = group_data
def set_group_state(self, group, state):
'''expand group id state is True, collapse it if False'''
for row in self._model:
obj = row[1]
if type(obj) == Group and obj.name == group.name:
path = self._model.get_path()
if state:
self.expand_row(path, False)
else:
self.collapse_row(path)
def format_nick(self, contact):
'''replace the appearance of the template vars using the values of
the contact
# valid values:
# + NICK
# + ACCOUNT
# + DISPLAY_NAME (alias if available, or nick if available or mail)
# + STATUS
# + MESSAGE
'''
template = self.nick_template
template = template.replace('%NICK%',
gobject.markup_escape_text(contact.nick))
template = template.replace('%ACCOUNT%',
gobject.markup_escape_text(contact.account))
template = template.replace('%MESSAGE%',
gobject.markup_escape_text(contact.message))
template = template.replace('%STATUS%',
gobject.markup_escape_text(status.STATUS[contact.status]))
template = template.replace('%DISPLAY_NAME%',
gobject.markup_escape_text(contact.display_name))
return template
def format_group(self, group):
'''replace the appearance of the template vars using the values of
the group
# valid values:
# + NAME
# + ONLINE_COUNT
# + TOTAL_COUNT
'''
contacts = self.contacts.get_contacts(group.contacts)
(online, total) = self.contacts.get_online_total_count(contacts)
template = self.group_template
template = template.replace('%NAME%',
gobject.markup_escape_text(group.name))
template = template.replace('%ONLINE_COUNT%', str(online))
template = template.replace('%TOTAL_COUNT%', str(total))
return template
def test():
import dialog
import string
import random
import ContactManager
import GroupManager
def _on_contact_selected(contact_list, contact):
'''callback for the contact-selected signal'''
print 'contact selected: ', contact.display_name
contact.nick = random_string()
contact.status = random.choice(status.ORDERED)
contact.message = random_string()
contact_list.update_contact(contact)
def _on_group_selected(contact_list, group):
'''callback for the group-selected signal'''
print 'group selected: ', group.name
group.name = random_string()
contact_list.update_group(group)
def _on_contact_menu_selected(contact_list, contact):
'''callback for the contact-menu-selected signal'''
print 'contact menu selected: ', contact.display_name
contact_list.remove_contact(contact)
def _on_group_menu_selected(contact_list, group):
'''callback for the group-menu-selected signal'''
print 'group menu selected: ', group.name
contact_list.remove_group(group)
def random_string(length=6):
'''generate a random string of length "length"'''
return ''.join([random.choice(string.ascii_letters) for i \
in range(length)])
def random_mail():
'''generate a random mail'''
return random_string() + '@' + random_string() + '.com'
contactm = ContactManager.ContactManager(dialog, None, 'msn@msn.com')
groupm = GroupManager.GroupManager(dialog, None)
window = gtk.Window()
window.set_default_size(200, 200)
scroll = gtk.ScrolledWindow()
conlist = ContactList(contactm, groupm, dialog)
conlist.signal_connect('contact-selected', _on_contact_selected)
conlist.signal_connect('contact-menu-selected', _on_contact_menu_selected)
conlist.signal_connect('group-selected', _on_group_selected)
conlist.signal_connect('group-menu-selected', _on_group_menu_selected)
conlist.order_by_status = True
conlist.show_offline = True
scroll.add(conlist)
window.add(scroll)
window.connect("delete-event", gtk.main_quit)
window.show_all()
for i in range(6):
group = Group(random_string())
groupm.register(group)
for j in range(6):
contact = Contact(random_mail(), i * 10 + j, random_string())
contact.status = random.choice(status.ORDERED)
contact.message = random_string()
group.contacts.append(contact.account)
contactm.register(contact)
conlist.add_contact(contact, group)
for j in range(6):
contact = Contact(random_mail(), 100 + j, random_string())
contact.status = random.choice(status.ORDERED)
contact.message = random_string()
contactm.register(contact)
conlist.add_contact(contact)
gtk.main()
if __name__ == '__main__':
test()
|