# -*- 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 abstract object that define the API of a contact list and some behavior'''
import status
import Object
class ContactList(Object.Object):
'''an abstract class that defines the api that the contact list should
have'''
def __init__(self, contacts, groups, dialog):
'''class constructor'''
Object.Object.__init__(self)
# define the class signals
# the param is the contact object
self.signal_add('contact-selected', 1)
# the param is the group object
self.signal_add('group-selected', 1)
# the signal is the contact object, the callback should display
# a contextual menu to do operations on the contact
self.signal_add('group-menu-selected', 1)
# the signal is the group object, the callback should display
# a contextual menu to do operations on the group
self.signal_add('contact-menu-selected', 1)
self.contacts = contacts
self.groups = groups
self.dialog = dialog
self.group_state = {}
# self.order_by_status is a property that resturn the inverse
# value as the one of order_by_status, the setter, set the inverse
# value to this attribute
self.order_by_group = True
self.show_nick = True
self.show_empty_groups = False
self.show_group_count = False
self._show_offline = False
self._filter_text = ''
# valid values:
# + NICK
# + ACCOUNT
# + DISPLAY_NAME (alias if available, or nick if available or mail)
# + STATUS
# + MESSAGE
self.nick_template = \
'%DISPLAY_NAME%\n%ACCOUNT%\n(%STATUS%) - %MESSAGE%'
# valid values:
# + NAME
# + ONLINE_COUNT
# + TOTAL_COUNT
self.group_template = '%NAME% (%ONLINE_COUNT%/%TOTAL_COUNT%)'
self._connect_signals()
def _connect_signals(self):
'''connect all the signals from ContactManager and GroupManager'''
self.contacts.signal_connect('contact-added', self._on_contact_added)
self.contacts.signal_connect('contact-removed',
self._on_contact_removed)
self.contacts.signal_connect('contact-changed',
self._on_contact_changed)
self.groups.signal_connect('group-added', self._on_group_added)
self.groups.signal_connect('group-removed', self._on_group_removed)
self.groups.signal_connect('group-changed', self._on_group_changed)
self.groups.signal_connect('contact-added-to-group',
self._on_contact_added_to_group)
self.groups.signal_connect('contact-removed-from-group',
self._on_contact_removed_from_group)
def _on_contact_added(self, contacts, contact):
'''callback called when a contact is added to the userlist'''
self.add_contact(contact)
def _on_contact_removed(self, contacts, contact):
'''callback called when a contact is removed from the userlist'''
self.remove_contact(contact)
def _on_contact_changed(self, contacts, contact, attr, old_value):
'''callback called when an attr changes on a contact'''
self.update_contact(contact)
def _on_group_added(self, groups, group):
'''called when a group is added'''
self.add_group(group)
def _on_group_removed(self, groups, group):
'''called when a group'''
self.remove_group(group)
def _on_group_changed(self, groups, group, attr, old_value):
'''called when an attr from a group changed'''
self.update_group(group)
def _on_contact_added_to_group(self, groups, account, group):
'''callback called when a contact is added to the a group'''
contact = self.contacts.contacts.get(account, None)
if contact:
self.add_contact(contact, group)
else:
print account, 'has no contact associated'
def _on_contact_removed_from_group(self, groups, account, group):
'''callback called when a contact is removed from the a group'''
contact = self.contacts.contacts.get(account, None)
if contact:
self.remove_contact(contact, group)
else:
print account, 'has no contact associated'
def _get_order_by_status(self):
'''return the value of order by status'''
return not self.order_by_group
def _set_order_by_status(self, value):
'''set the value of order by status'''
self.order_by_group = not value
order_by_status = property(fget=_get_order_by_status,
fset=_set_order_by_status)
def _get_show_offline(self):
'''return the value of self._show_offline'''
return self._show_offline
def _set_show_offline(self, value):
'''set the value of self._show_offline to value and call to
self.refilter()'''
self._show_offline = value
self.refilter()
show_offline = property(fget=_get_show_offline, fset=_set_show_offline)
def _get_filter_text(self):
'''return the filter_text value'''
return self._filter_text
def _set_filter_text(self, value):
'''set the filter_text value'''
self._filter_text = value
self.refilter()
filter_text = property(fget=_get_filter_text, fset=_set_filter_text)
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%', contact.nick)
template = template.replace('%ACCOUNT%', contact.account)
template = template.replace('%MESSAGE%', contact.message)
template = template.replace('%STATUS%', status.STATUS[contact.status])
template = template.replace('%DISPLAY_NAME%', 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%', group.name)
template = template.replace('%ONLINE_COUNT%', str(online))
template = template.replace('%TOTAL_COUNT%', str(total))
return template
def refilter(self):
'''refilter the values according to the value of self.filter_text'''
raise NotImplementedError
def is_group_selected(self):
'''return True if a group is selected'''
raise NotImplementedError
def is_contact_selected(self):
'''return True if a contact is selected'''
raise NotImplementedError
def get_group_selected(self):
'''return a group object if there is a group selected, None otherwise
'''
raise NotImplementedError
def get_contact_selected(self):
'''return a contact object if there is a group selected, None otherwise
'''
raise NotImplementedError
def add_group(self, group):
'''add a group to the contact list'''
raise NotImplementedError
def remove_group(self, group):
'''remove a group from the contact list'''
raise NotImplementedError
def add_contact(self, contact, group=None):
'''add a contact to the contact list, add it to the group if
group is not None'''
raise NotImplementedError
def remove_contact(self, contact, group=None):
'''remove a contact from thespecifiedgroupgroupNone import
then remove him from allgroups import
raise NotImplementedError
def fill(self):
'''fill the contact list with the contacts and groups from import
self.contacts and self.groups'''
for group in self.groups.groups:
# get a list of contact objects from a list of accounts
contacts = self.contacts.get_contacts(group.contacts)
for contact in contacts:
self.add_contact(contact, group)
for contact in self.contacts.get_no_group():
self.add_contact(contact)
def clear(self):
'''clear the contact list'''
raise NotImplementedError
def update_contact(self, contact):
'''update the data of contact'''
raise NotImplementedError
def update_group(self, group):
'''update the data of group'''
raise NotImplementedError
def set_group_state(self, group, state):
'''expand group id state is True, collapse it if False'''
raise NotImplementedError
def expand_collapse_groups(self):
'''expand and collapse the groups according to the state of the
group'''
for (group, state) in self.group_state.iteritems():
self.set_group_state(group, state)
def on_group_collapsed(self, group):
'''called when a group is collapsed, update the status of the
groups'''
self.group_state.update({group.name:False})
def on_group_expanded(self, group):
'''called when a group is expanded, update the status of the
groups'''
self.group_state.update({group.name:True})
def compare_groups(self, group1, group2):
'''compare two groups and return 1 if group1 should go first, 0
if equal, -1 if group2 should go first'''
return cmp(group1.name, group2.name)
def compare_contacts(self, contact1, contact2):
'''compare two contacts and return 1 if contact1 should go first, 0
if equal and -1 if contact2 should go first'''
result = cmp(status.ORDERED.index(contact1.status),
status.ORDERED.index(contact2.status))
if result != 0:
return result
if self.order_by_status:
return cmp(contact1.display_name, contact2.display_name)
if len(contact1.groups) == 0:
if len(contact2.groups) == 0:
return cmp(contact1.display_name, contact2.display_name)
else:
return -1
elif len(contact2.groups) == 0:
return 1
else:
return cmp(contact1.display_name, contact2.display_name)
|