1
# -*- coding: utf-8 -*-
3
# This file is part of emesene.
5
# Emesene is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
10
# emesene is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with emesene; if not, write to the Free Software
17
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
'''a abstract object that define the API of a contact list and some behavior'''
22
class ContactList(Object.Object):
23
'''an abstract class that defines the api that the contact list should
26
def __init__(self, contacts, groups, dialog):
27
'''class constructor'''
28
Object.Object.__init__(self)
30
# define the class signals
31
# the param is the contact object
32
self.signal_add('contact-selected', 1)
33
# the param is the group object
34
self.signal_add('group-selected', 1)
35
# the signal is the contact object, the callback should display
36
# a contextual menu to do operations on the contact
37
self.signal_add('group-menu-selected', 1)
38
# the signal is the group object, the callback should display
39
# a contextual menu to do operations on the group
40
self.signal_add('contact-menu-selected', 1)
42
self.contacts = contacts
47
# self.order_by_status is a property that resturn the inverse
48
# value as the one of order_by_status, the setter, set the inverse
49
# value to this attribute
50
self.order_by_group = True
52
self.show_empty_groups = False
53
self.show_group_count = False
54
self._show_offline = False
56
self._filter_text = ''
61
# + DISPLAY_NAME (alias if available, or nick if available or mail)
64
self.nick_template = \
65
'%DISPLAY_NAME%\n%ACCOUNT%\n(%STATUS%) - %MESSAGE%'
70
self.group_template = '%NAME% (%ONLINE_COUNT%/%TOTAL_COUNT%)'
72
self._connect_signals()
74
def _connect_signals(self):
75
'''connect all the signals from ContactManager and GroupManager'''
76
self.contacts.signal_connect('contact-added', self._on_contact_added)
77
self.contacts.signal_connect('contact-removed',
78
self._on_contact_removed)
79
self.contacts.signal_connect('contact-changed',
80
self._on_contact_changed)
82
self.groups.signal_connect('group-added', self._on_group_added)
83
self.groups.signal_connect('group-removed', self._on_group_removed)
84
self.groups.signal_connect('group-changed', self._on_group_changed)
85
self.groups.signal_connect('contact-added-to-group',
86
self._on_contact_added_to_group)
87
self.groups.signal_connect('contact-removed-from-group',
88
self._on_contact_removed_from_group)
90
def _on_contact_added(self, contacts, contact):
91
'''callback called when a contact is added to the userlist'''
92
self.add_contact(contact)
94
def _on_contact_removed(self, contacts, contact):
95
'''callback called when a contact is removed from the userlist'''
96
self.remove_contact(contact)
98
def _on_contact_changed(self, contacts, contact, attr, old_value):
99
'''callback called when an attr changes on a contact'''
100
self.update_contact(contact)
102
def _on_group_added(self, groups, group):
103
'''called when a group is added'''
104
self.add_group(group)
106
def _on_group_removed(self, groups, group):
107
'''called when a group'''
108
self.remove_group(group)
110
def _on_group_changed(self, groups, group, attr, old_value):
111
'''called when an attr from a group changed'''
112
self.update_group(group)
114
def _on_contact_added_to_group(self, groups, account, group):
115
'''callback called when a contact is added to the a group'''
116
contact = self.contacts.contacts.get(account, None)
118
self.add_contact(contact, group)
120
print account, 'has no contact associated'
122
def _on_contact_removed_from_group(self, groups, account, group):
123
'''callback called when a contact is removed from the a group'''
124
contact = self.contacts.contacts.get(account, None)
126
self.remove_contact(contact, group)
128
print account, 'has no contact associated'
130
def _get_order_by_status(self):
131
'''return the value of order by status'''
132
return not self.order_by_group
134
def _set_order_by_status(self, value):
135
'''set the value of order by status'''
136
self.order_by_group = not value
138
order_by_status = property(fget=_get_order_by_status,
139
fset=_set_order_by_status)
141
def _get_show_offline(self):
142
'''return the value of self._show_offline'''
143
return self._show_offline
145
def _set_show_offline(self, value):
146
'''set the value of self._show_offline to value and call to
148
self._show_offline = value
151
show_offline = property(fget=_get_show_offline, fset=_set_show_offline)
153
def _get_filter_text(self):
154
'''return the filter_text value'''
155
return self._filter_text
157
def _set_filter_text(self, value):
158
'''set the filter_text value'''
159
self._filter_text = value
162
filter_text = property(fget=_get_filter_text, fset=_set_filter_text)
164
def format_nick(self, contact):
165
'''replace the appearance of the template vars using the values of
170
# + DISPLAY_NAME (alias if available, or nick if available or mail)
174
template = self.nick_template
175
template = template.replace('%NICK%', contact.nick)
176
template = template.replace('%ACCOUNT%', contact.account)
177
template = template.replace('%MESSAGE%', contact.message)
178
template = template.replace('%STATUS%', status.STATUS[contact.status])
179
template = template.replace('%DISPLAY_NAME%', contact.display_name)
183
def format_group(self, group):
184
'''replace the appearance of the template vars using the values of
191
contacts = self.contacts.get_contacts(group.contacts)
192
(online, total) = self.contacts.get_online_total_count(contacts)
193
template = self.group_template
194
template = template.replace('%NAME%', group.name)
195
template = template.replace('%ONLINE_COUNT%', str(online))
196
template = template.replace('%TOTAL_COUNT%', str(total))
201
'''refilter the values according to the value of self.filter_text'''
202
raise NotImplementedError
204
def is_group_selected(self):
205
'''return True if a group is selected'''
206
raise NotImplementedError
208
def is_contact_selected(self):
209
'''return True if a contact is selected'''
210
raise NotImplementedError
212
def get_group_selected(self):
213
'''return a group object if there is a group selected, None otherwise
215
raise NotImplementedError
217
def get_contact_selected(self):
218
'''return a contact object if there is a group selected, None otherwise
220
raise NotImplementedError
222
def add_group(self, group):
223
'''add a group to the contact list'''
224
raise NotImplementedError
226
def remove_group(self, group):
227
'''remove a group from the contact list'''
228
raise NotImplementedError
230
def add_contact(self, contact, group=None):
231
'''add a contact to the contact list, add it to the group if
233
raise NotImplementedError
235
def remove_contact(self, contact, group=None):
236
'''remove a contact from the specified group, if group is None
237
then remove him from all groups'''
238
raise NotImplementedError
241
'''fill the contact list with the contacts and groups from
242
self.contacts and self.groups'''
243
for group in self.groups.groups:
244
# get a list of contact objects from a list of accounts
245
contacts = self.contacts.get_contacts(group.contacts)
246
for contact in contacts:
247
self.add_contact(contact, group)
249
for contact in self.contacts.get_no_group():
250
self.add_contact(contact)
253
'''clear the contact list'''
254
raise NotImplementedError
256
def update_contact(self, contact):
257
'''update the data of contact'''
258
raise NotImplementedError
260
def update_group(self, group):
261
'''update the data of group'''
262
raise NotImplementedError
264
def set_group_state(self, group, state):
265
'''expand group id state is True, collapse it if False'''
266
raise NotImplementedError
268
def expand_collapse_groups(self):
269
'''expand and collapse the groups according to the state of the
271
for (group, state) in self.group_state.iteritems():
272
self.set_group_state(group, state)
274
def on_group_collapsed(self, group):
275
'''called when a group is collapsed, update the status of the
277
self.group_state.update({group.name:False})
279
def on_group_expanded(self, group):
280
'''called when a group is expanded, update the status of the
282
self.group_state.update({group.name:True})
284
def compare_groups(self, group1, group2):
285
'''compare two groups and return 1 if group1 should go first, 0
286
if equal, -1 if group2 should go first'''
288
return cmp(group1.name, group2.name)
290
def compare_contacts(self, contact1, contact2):
291
'''compare two contacts and return 1 if contact1 should go first, 0
292
if equal and -1 if contact2 should go first'''
294
result = cmp(status.ORDERED.index(contact1.status),
295
status.ORDERED.index(contact2.status))
300
if self.order_by_status:
301
return cmp(contact1.display_name, contact2.display_name)
303
if len(contact1.groups) == 0:
304
if len(contact2.groups) == 0:
305
return cmp(contact1.display_name, contact2.display_name)
308
elif len(contact2.groups) == 0:
311
return cmp(contact1.display_name, contact2.display_name)