Don't remove contacts from roster when they have pending events.

* update documentation and fix indentation
 * don't remove offline contacts from roster when we open the last pending, non chat message event
 * store account and jid per event
This commit is contained in:
Stephan Erb 2008-05-30 17:42:53 +00:00
parent 8973b91070
commit 4b6fabadd9
3 changed files with 105 additions and 101 deletions

View File

@ -48,6 +48,9 @@ class Event:
self.parameters = parameters self.parameters = parameters
self.show_in_roster = show_in_roster self.show_in_roster = show_in_roster
self.show_in_systray = show_in_systray self.show_in_systray = show_in_systray
# Set when adding the event
self.jid = None
self.account = None
class Events: class Events:
'''Information concerning all events''' '''Information concerning all events'''
@ -112,6 +115,8 @@ class Events:
self._events[account][jid] = [event] self._events[account][jid] = [event]
else: else:
self._events[account][jid].append(event) self._events[account][jid].append(event)
event.jid = jid
event.account = account
self.fire_event_added(event) self.fire_event_added(event)
def remove_events(self, account, jid, event = None, types = []): def remove_events(self, account, jid, event = None, types = []):

View File

@ -1573,22 +1573,7 @@ class Interface:
not name and not groups: not name and not groups:
if contacts: if contacts:
c = contacts[0] c = contacts[0]
self.roster.remove_contact(c.jid, account) self.roster.remove_contact(c.jid, account, backend = True)
gajim.contacts.remove_jid(account, jid)
self.roster.draw_account(account)
if gajim.events.get_events(account, c.jid):
keyID = ''
attached_keys = gajim.config.get_per('accounts', account,
'attached_gpg_keys').split()
if jid in attached_keys:
keyID = attached_keys[attached_keys.index(jid) + 1]
contact = gajim.contacts.create_contact(jid = c.jid,
name = '', groups = [_('Not in Roster')],
show = 'not in roster', status = '', sub = 'none',
keyID = keyID)
gajim.contacts.add_contact(account, contact)
self.roster.add_contact(contact.jid, account)
#FIXME if it was the only one in its group, remove the group
return return
elif not contacts: elif not contacts:
if sub == 'remove': if sub == 'remove':
@ -1602,7 +1587,7 @@ class Interface:
re_add = False re_add = False
# if sub changed: remove and re-add, maybe observer status changed # if sub changed: remove and re-add, maybe observer status changed
if contacts[0].sub != sub: if contacts[0].sub != sub:
self.roster.remove_contact(contacts[0].jid, account) self.roster.remove_contact(contacts[0].jid, account, force = True)
re_add = True re_add = True
for contact in contacts: for contact in contacts:
if not name: if not name:
@ -1614,7 +1599,6 @@ class Interface:
contact.groups = groups contact.groups = groups
if re_add: if re_add:
self.roster.add_contact(jid, account) self.roster.add_contact(jid, account)
self.roster.draw_contact(jid, account)
if self.remote_ctrl: if self.remote_ctrl:
self.remote_ctrl.raise_signal('RosterInfo', (account, array)) self.remote_ctrl.raise_signal('RosterInfo', (account, array))
@ -2405,26 +2389,6 @@ class Interface:
# Select the contact in roster, it's visible because it has events. # Select the contact in roster, it's visible because it has events.
self.roster.select_contact(jid, account) self.roster.select_contact(jid, account)
def remove_first_event(self, account, jid, type_ = None):
event = gajim.events.get_first_event(account, jid, type_)
self.remove_event(account, jid, event)
def remove_event(self, account, jid, event):
if gajim.events.remove_events(account, jid, event):
# No such event found
return
# no other event?
if not len(gajim.events.get_events(account, jid)):
contact = gajim.contacts.get_contact_with_highest_priority(account,
jid)
show_transport = gajim.config.get('show_transports_group')
if contact and (contact.show in ('error', 'offline') and \
not gajim.config.get('showoffline') or (
gajim.jid_is_transport(jid) and not show_transport)):
self.roster.remove_contact(contact.jid, account)
self.roster.show_title()
self.roster.draw_contact(jid, account)
def handle_event(self, account, fjid, type_): def handle_event(self, account, fjid, type_):
w = None w = None
resource = gajim.get_resource_from_jid(fjid) resource = gajim.get_resource_from_jid(fjid)

View File

@ -154,11 +154,11 @@ class RosterWindow:
def _get_contact_iter(self, jid, account, contact = None, model = None): def _get_contact_iter(self, jid, account, contact = None, model = None):
''' Return a list of gtk.TreeIter of the given contact. ''' Return a list of gtk.TreeIter of the given contact.
Keyword arguments: Keyword arguments:
jid -- the jid without resource jid -- the jid without resource
account -- the account account -- the account
contact -- the contact (default None) contact -- the contact (default None)
model -- the data model (default TreeFilterModel) model -- the data model (default TreeFilterModel)
''' '''
if not model: if not model:
@ -220,7 +220,7 @@ class RosterWindow:
''' Return True if the given iter is a separator. ''' Return True if the given iter is a separator.
Keyword arguments: Keyword arguments:
model -- the data model model -- the data model
iter -- the gtk.TreeIter to test iter -- the gtk.TreeIter to test
''' '''
if model[titer][0] == 'SEPARATOR': if model[titer][0] == 'SEPARATOR':
@ -231,8 +231,8 @@ class RosterWindow:
def _iter_contact_rows(self, model = None): def _iter_contact_rows(self, model = None):
'''Iterate over all contact rows in given model. '''Iterate over all contact rows in given model.
Keyword arguments: Keyword argument
model -- the data model (default TreeFilterModel) model -- the data model (default TreeFilterModel)
''' '''
if not model: if not model:
model = self.modelfilter model = self.modelfilter
@ -328,9 +328,9 @@ class RosterWindow:
Keyword arguments: Keyword arguments:
contact -- the contact to add contact -- the contact to add
account -- the contacts account account -- the contacts account
groups -- list of groups to add the contact to. (default groups in contact.groups). groups -- list of groups to add the contact to. (default groups in contact.groups).
Parameter ignored when big_brother_contact is specified. Parameter ignored when big_brother_contact is specified.
big_brother_contact -- if specified contact is added as child big_brother_contact. (default None) big_brother_contact -- if specified contact is added as child big_brother_contact. (default None)
''' '''
added_iters = [] added_iters = []
@ -405,8 +405,8 @@ class RosterWindow:
Keyword arguments: Keyword arguments:
contact -- the contact to add contact -- the contact to add
account -- the contacts account account -- the contacts account
groups -- list of groups to remove the contact from. (default groups in contact.groups). groups -- list of groups to remove the contact from. (default groups in contact.groups).
''' '''
iters = self._get_contact_iter(contact.jid, account, contact, self.model) iters = self._get_contact_iter(contact.jid, account, contact, self.model)
@ -650,7 +650,7 @@ class RosterWindow:
return contacts[0][0] # it's contact/big brother with highest priority return contacts[0][0] # it's contact/big brother with highest priority
def remove_contact(self, jid, account): def remove_contact(self, jid, account, force = False, backend = False):
'''Remove contact from roster. '''Remove contact from roster.
Remove contact from all its group. Remove empty groups or redraw otherwise. Remove contact from all its group. Remove empty groups or redraw otherwise.
@ -661,6 +661,8 @@ class RosterWindow:
Keyword arguments: Keyword arguments:
jid -- the contact's jid or SelfJid to remove SelfContact jid -- the contact's jid or SelfJid to remove SelfContact
account -- the corresponding account. account -- the corresponding account.
force -- remove contact even it has pending evens (Default False)
backend -- also remove contact instance (Default False)
''' '''
contact = gajim.contacts.get_contact_with_highest_priority(account, jid) contact = gajim.contacts.get_contact_with_highest_priority(account, jid)
@ -669,27 +671,40 @@ class RosterWindow:
if not iters: if not iters:
return return
# Remove contact from roster if not force and self.contact_has_pending_roster_events(contact, account):
family = gajim.contacts.get_metacontacts_family(account, jid) # Contact has pending events
if family: key = (jid, account)
# We have a family. So we are a metacontact. if not key in self.contacts_to_be_removed.keys():
self._remove_metacontact_family(family, account) self.contacts_to_be_removed[key] = {'backend': backend}
else: return False
self._remove_entity(contact, account) else:
# no more pending events
# Remove contact from roster directly
family = gajim.contacts.get_metacontacts_family(account, jid)
if family:
# We have a family. So we are a metacontact.
self._remove_metacontact_family(family, account)
else:
self._remove_entity(contact, account)
# Draw all groups of the contact # Draw all groups of the contact
groups = contact.groups groups = contact.groups
if contact.is_observer(): if contact.is_observer():
contact.groups = [_('Observers')] contact.groups = [_('Observers')]
if not groups: if not groups:
groups = [_('General')] groups = [_('General')]
for group in groups:
self.draw_group(group, account) if backend:
# Remove contact before redrawing, otherwise the old
# numbers will still be show
gajim.contacts.remove_jid(account, jid)
for group in groups:
self.draw_group(group, account)
self.draw_account(account)
return True
self.draw_account(account)
return True
def add_groupchat(self, jid, account, status = ''): def add_groupchat(self, jid, account, status = ''):
'''Add groupchat to roster and draw it. '''Add groupchat to roster and draw it.
@ -711,12 +726,7 @@ class RosterWindow:
def remove_groupchat(self, jid, account): def remove_groupchat(self, jid, account):
'''Remove groupchat from roster and redraw account and group.''' '''Remove groupchat from roster and redraw account and group.'''
contact = gajim.contacts.get_contact_with_highest_priority(account, jid) contact = gajim.contacts.get_contact_with_highest_priority(account, jid)
self.remove_contact(jid, account) self.remove_contact(jid, account, force = True, backend = True)
gajim.contacts.remove_contact(account, contact)
# When we redraw the group in remove_contact the
# contact does still exist and so the group is still showing
# the old numbers.
self.draw_group(_('Groupchats'), account)
return True return True
@ -737,15 +747,9 @@ class RosterWindow:
def remove_transport(self, jid, account): def remove_transport(self, jid, account):
'''Remove transport from roster and redraw account and group.''' '''Remove transport from roster and redraw account and group.'''
contact = gajim.contacts.get_contact_with_highest_priority(account, jid) contact = gajim.contacts.get_contact_with_highest_priority(account, jid)
self.remove_contact(jid, account) self.remove_contact(jid, account, force = True, backend = True)
gajim.contacts.remove_contact(account, contact)
# When we redraw the group in remove_contact the
# contact does still exist and so the group is still showing
# the old numbers.
self.draw_group(_('Transports'), account)
return True return True
#FIXME: #FIXME:
# We need to define a generic way to keep contacts in roster # We need to define a generic way to keep contacts in roster
# as long as they have pending events or as we # as long as they have pending events or as we
@ -771,6 +775,7 @@ class RosterWindow:
gajim.contacts.add_contact(account, c) gajim.contacts.add_contact(account, c)
self.add_contact(contact.jid, account) self.add_contact(contact.jid, account)
def add_contact_to_groups(self, jid, account, groups): def add_contact_to_groups(self, jid, account, groups):
'''Add contact to given groups and redraw them. '''Add contact to given groups and redraw them.
@ -783,7 +788,7 @@ class RosterWindow:
groups -- list of Groups to add the contact too. groups -- list of Groups to add the contact too.
''' '''
self.remove_contact(jid, account) self.remove_contact(jid, account, force = True)
for contact in gajim.contacts.get_contacts(account, jid): for contact in gajim.contacts.get_contacts(account, jid):
for group in groups: for group in groups:
@ -809,7 +814,7 @@ class RosterWindow:
groups -- list of Groups to remove the contact from groups -- list of Groups to remove the contact from
''' '''
self.remove_contact(jid, account) self.remove_contact(jid, account, force = True)
for contact in gajim.contacts.get_contacts(account, jid): for contact in gajim.contacts.get_contacts(account, jid):
for group in groups: for group in groups:
@ -843,6 +848,9 @@ class RosterWindow:
#FIXME: integrate into add_contact() #FIXME: integrate into add_contact()
def add_to_not_in_the_roster(self, account, jid, nick = '', resource = ''): def add_to_not_in_the_roster(self, account, jid, nick = '', resource = ''):
print "add to not in the roster"
import traceback
traceback.print_stack()
keyID = '' keyID = ''
attached_keys = gajim.config.get_per('accounts', account, attached_keys = gajim.config.get_per('accounts', account,
'attached_gpg_keys').split() 'attached_gpg_keys').split()
@ -1238,7 +1246,7 @@ class RosterWindow:
def select_contact(self, jid, account): def select_contact(self, jid, account):
'''Select contact in roster. If contact is hidden but has eventsi, '''Select contact in roster. If contact is hidden but has events,
show him.''' show him.'''
# Refiltering SHOULD NOT be needed: # Refiltering SHOULD NOT be needed:
# When a contact gets a new event he will be redrawn and his # When a contact gets a new event he will be redrawn and his
@ -1299,16 +1307,22 @@ class RosterWindow:
self.filtering = True self.filtering = True
self.modelfilter.refilter() self.modelfilter.refilter()
self.filtering = False self.filtering = False
def contact_is_visible(self, contact, account): def contact_has_pending_roster_events(self, contact, account):
# show it if pending events ''' Return True if the contact or one if it resources has pending events'''
# jid has pending events
if gajim.events.get_nb_roster_events(account, contact.jid) > 0: if gajim.events.get_nb_roster_events(account, contact.jid) > 0:
return True return True
# count events from all resources # check events of all resources
for contact_ in gajim.contacts.get_contacts(account, contact.jid): for contact_ in gajim.contacts.get_contacts(account, contact.jid):
if contact_.resource and gajim.events.get_nb_roster_events(account, if contact_.resource and gajim.events.get_nb_roster_events(account,
contact_.get_full_jid()) > 0: contact_.get_full_jid()) > 0:
return True return True
return False
def contact_is_visible(self, contact, account):
if self.contact_has_pending_roster_events(contact, account):
return True
# XEP-0162 # XEP-0162
hide = contact.is_hidden_from_roster() hide = contact.is_hidden_from_roster()
if hide and contact.sub != 'from': if hide and contact.sub != 'from':
@ -1639,6 +1653,24 @@ class RosterWindow:
minimize = bm['minimize'] in ('1', 'true') minimize = bm['minimize'] in ('1', 'true')
gajim.interface.join_gc_room(account, jid, bm['nick'], gajim.interface.join_gc_room(account, jid, bm['nick'],
bm['password'], minimize = minimize) bm['password'], minimize = minimize)
def on_event_removed(self, event_list):
'''Remove contacts on last events removed.
Only performed if removal was requested before but the contact
still had pending events
'''
no_more_pending = ((event.jid.split('/')[0], event.account) for event in event_list
if len(gajim.events.get_events(event.account, event.jid)))
for jid, account in no_more_pending:
self.draw_contact(jid, account)
# Remove contacts in roster if removal was requested
key = (jid, account)
if key in self.contacts_to_be_removed.keys():
del self.contacts_to_be_removed[key]
self.remove_contact(jid, account, backend = True)
self.show_title()
def open_event(self, account, jid, event): def open_event(self, account, jid, event):
'''If an event was handled, return True, else return False''' '''If an event was handled, return True, else return False'''
@ -1648,31 +1680,31 @@ class RosterWindow:
dialogs.SingleMessageWindow(account, jid, dialogs.SingleMessageWindow(account, jid,
action='receive', from_whom=jid, subject=data[1], message=data[0], action='receive', from_whom=jid, subject=data[1], message=data[0],
resource=data[5], session=data[8], form_node=data[9]) resource=data[5], session=data[8], form_node=data[9])
gajim.interface.remove_first_event(account, jid, event.type_) gajim.events.get_first_event(account, jid, event.type_)
return True return True
elif event.type_ == 'file-request': elif event.type_ == 'file-request':
contact = gajim.contacts.get_contact_with_highest_priority(account, contact = gajim.contacts.get_contact_with_highest_priority(account,
jid) jid)
gajim.interface.remove_first_event(account, jid, event.type_) gajim.events.get_first_event(account, jid, event.type_)
ft.show_file_request(account, contact, data) ft.show_file_request(account, contact, data)
return True return True
elif event.type_ in ('file-request-error', 'file-send-error'): elif event.type_ in ('file-request-error', 'file-send-error'):
gajim.interface.remove_first_event(account, jid, event.type_) gajim.events.get_first_event(account, jid, event.type_)
ft.show_send_error(data) ft.show_send_error(data)
return True return True
elif event.type_ in ('file-error', 'file-stopped'): elif event.type_ in ('file-error', 'file-stopped'):
gajim.interface.remove_first_event(account, jid, event.type_) gajim.events.get_first_event(account, jid, event.type_)
ft.show_stopped(jid, data) ft.show_stopped(jid, data)
return True return True
elif event.type_ == 'file-completed': elif event.type_ == 'file-completed':
gajim.interface.remove_first_event(account, jid, event.type_) gajim.events.get_first_event(account, jid, event.type_)
ft.show_completed(jid, data) ft.show_completed(jid, data)
return True return True
elif event.type_ == 'gc-invitation': elif event.type_ == 'gc-invitation':
dialogs.InvitationReceivedDialog(account, data[0], jid, data[2], dialogs.InvitationReceivedDialog(account, data[0], jid, data[2],
data[1]) data[1])
gajim.interface.remove_first_event(account, jid, event.type_) gajim.events.get_first_event(account, jid, event.type_)
return True return True
return False return False
################################################################################ ################################################################################
@ -2311,14 +2343,14 @@ class RosterWindow:
def on_remove_agent(self, widget, list_): def on_remove_agent(self, widget, list_):
'''When an agent is requested to be removed. list_ is a list of '''When an agent is requested to be removed. list_ is a list of
(contact, account) tuple''' (contact, account) tuple'''
# FIXME remove transport contacts
for (contact, account) in list_: for (contact, account) in list_:
if gajim.config.get_per('accounts', account, 'hostname') == \ if gajim.config.get_per('accounts', account, 'hostname') == \
contact.jid: contact.jid:
# We remove the server contact # We remove the server contact
# remove it from treeview # remove it from treeview
gajim.connections[account].unsubscribe(contact.jid) gajim.connections[account].unsubscribe(contact.jid)
self.remove_contact(contact.jid, account) self.remove_contact(contact.jid, account, backend = True)
gajim.contacts.remove_contact(account, contact)
return return
def remove(list_): def remove(list_):
@ -2326,9 +2358,7 @@ class RosterWindow:
full_jid = contact.get_full_jid() full_jid = contact.get_full_jid()
gajim.connections[account].unsubscribe_agent(full_jid) gajim.connections[account].unsubscribe_agent(full_jid)
# remove transport from treeview # remove transport from treeview
self.remove_contact(contact.jid, account) self.remove_contact(contact.jid, account, backend = True)
gajim.contacts.remove_jid(account, contact.jid)
gajim.contacts.remove_contact(account, contact)
# Check if there are unread events from some contacts # Check if there are unread events from some contacts
has_unread_events = False has_unread_events = False
@ -5751,6 +5781,11 @@ class RosterWindow:
# Workaroung: For strange reasons signal is behaving like row-changed # Workaroung: For strange reasons signal is behaving like row-changed
self._toggeling_row = False self._toggeling_row = False
# Remove contact from roster when last event opened
# { (contact, account): { backend: boolean }
self.contacts_to_be_removed = {}
gajim.events.event_removed_subscribe(self.on_event_removed)
# when this value become 0 we quit main application. If it's more than 0 # when this value become 0 we quit main application. If it's more than 0
# it means we are waiting for this number of accounts to disconnect before # it means we are waiting for this number of accounts to disconnect before
# quitting # quitting