From a67eaba727485b353c01aed5dfa7eb8b54c24a40 Mon Sep 17 00:00:00 2001 From: Yann Leboulanger <asterix@lagaule.org> Date: Sat, 2 Sep 2006 21:01:11 +0000 Subject: [PATCH] events are now saved in an Event class. show in roster/systray options in Advanced Notification Control (for incomming messages) now work. --- src/chat_control.py | 165 +++++++++++++++----------- src/common/events.py | 230 ++++++++++++++++++++++++++++++++++++ src/common/gajim.py | 23 +--- src/common/helpers.py | 24 +++- src/config.py | 17 +-- src/filetransfers_window.py | 11 +- src/gajim.py | 123 +++++++++---------- src/groupchat_control.py | 23 ++-- src/message_control.py | 6 +- src/message_window.py | 9 +- src/notify.py | 51 ++++---- src/remote_control.py | 2 +- src/roster_window.py | 91 +++++++------- src/systray.py | 37 ++---- src/systraywin32.py | 54 ++------- src/tooltips.py | 42 ++----- 16 files changed, 540 insertions(+), 368 deletions(-) create mode 100644 src/common/events.py diff --git a/src/chat_control.py b/src/chat_control.py index f3d7a4d655..e175590250 100644 --- a/src/chat_control.py +++ b/src/chat_control.py @@ -24,6 +24,7 @@ import gtkgui_helpers import message_control import dialogs import history_window +import notify from common import gajim from common import helpers @@ -50,7 +51,7 @@ class ChatControlBase(MessageControl): theme = gajim.config.get('roster_theme') bannerfont = gajim.config.get_per('themes', theme, 'bannerfont') bannerfontattrs = gajim.config.get_per('themes', theme, 'bannerfontattrs') - + if bannerfont: font = pango.FontDescription(bannerfont) else: @@ -61,16 +62,26 @@ class ChatControlBase(MessageControl): font.set_weight(pango.WEIGHT_HEAVY) if 'I' in bannerfontattrs: font.set_style(pango.STYLE_ITALIC) - + font_attrs = 'font_desc="%s"' % font.to_string() - + # in case there is no font specified we use x-large font size if font.get_size() == 0: font_attrs = '%s size="x-large"' % font_attrs font.set_weight(pango.WEIGHT_NORMAL) font_attrs_small = 'font_desc="%s" size="small"' % font.to_string() return (font_attrs, font_attrs_small) - + + def get_nb_unread(self): + jid = self.contact.jid + if self.resource: + jid += '/' + self.resource + type_ = self.type_id + if type_ == message_control.TYPE_GC: + type_ = 'gc_msg' + return len(gajim.events.get_events(self.account, jid, ['printed_' + type_, + type_])) + def draw_banner(self): self._paint_banner() self._update_banner_state_image() @@ -99,7 +110,7 @@ class ChatControlBase(MessageControl): widget = self.xml.get_widget('emoticons_button') id = widget.connect('clicked', self.on_emoticons_button_clicked) self.handlers[id] = widget - + id = self.widget.connect('key_press_event', self._on_keypress_event) self.handlers[id] = self.widget @@ -107,10 +118,10 @@ class ChatControlBase(MessageControl): id = widget.connect('button-press-event', self._on_banner_eventbox_button_press_event) self.handlers[id] = widget - + # Create textviews and connect signals self.conv_textview = ConversationTextview(self.account) - + self.conv_scrolledwindow = self.xml.get_widget( 'conversation_scrolledwindow') self.conv_scrolledwindow.add(self.conv_textview.tv) @@ -144,8 +155,6 @@ class ChatControlBase(MessageControl): self.typing_new = False self.orig_msg = '' - self.nb_unread = 0 - # Emoticons menu # set image no matter if user wants at this time emoticons or not # (so toggle works ok) @@ -480,12 +489,25 @@ class ChatControlBase(MessageControl): gajim.last_message_time[self.account][full_jid] = time.time() urgent = True if (not self.parent_win.get_active_jid() or \ - full_jid != self.parent_win.get_active_jid() or \ - not self.parent_win.is_active() or not end) and \ - kind in ('incoming', 'incoming_queue'): - self.nb_unread += 1 - if gajim.interface.systray_capabilities and self.notify_on_new_messages(): - gajim.interface.systray.add_jid(full_jid, self.account, self.type_id) + full_jid != self.parent_win.get_active_jid() or \ + not self.parent_win.is_active() or not end) and \ + kind in ('incoming', 'incoming_queue'): + if self.notify_on_new_messages(): + type_ = 'printed_' + self.type_id + if self.type_id == message_control.TYPE_GC: + type_ = 'printed_gc_msg' + show_in_roster = notify.get_show_in_roster('message_received', + self.account, self.contact) + show_in_systray = notify.get_show_in_systray('message_received', + self.account, self.contact) + event = gajim.events.create_event(type_, None, + show_in_roster = show_in_roster, + show_in_systray = show_in_systray) + gajim.events.add_event(self.account, full_jid, event) + # We need to redraw contact if we show in roster + if show_in_roster: + gajim.interface.roster.draw_contact(self.contact.jid, + self.account) self.parent_win.redraw_tab(self) if not self.parent_win.is_active(): ctrl = gajim.interface.msg_win_mgr.get_control(full_jid, @@ -510,6 +532,7 @@ class ChatControlBase(MessageControl): else: # we are the beginning of buffer buffer.insert_at_cursor('%s ' % str_) self.msg_textview.grab_focus() + def on_emoticons_button_clicked(self, widget): '''popup emoticons menu''' gajim.interface.emoticon_menuitem_clicked = self.append_emoticon @@ -554,15 +577,18 @@ class ChatControlBase(MessageControl): if state: jid = self.contact.jid if self.conv_textview.at_the_end(): - #we are at the end - if self.nb_unread > 0: - self.nb_unread = self.get_specific_unread() + # we are at the end + type_ = 'printed_' + self.type_id + if self.type_id == message_control.TYPE_GC: + type_ = 'printed_gc_msg' + if not gajim.events.remove_events(self.account, self.get_full_jid(), + types = [type_]): + # There were events to remove self.parent_win.redraw_tab(self) self.parent_win.show_title() - if gajim.interface.systray_capabilities: - gajim.interface.systray.remove_jid(self.get_full_jid(), - self.account, - self.type_id) + # redraw roster + gajim.interface.roster.draw_contact(jid, self.account) + gajim.interface.roster.show_title() self.msg_textview.grab_focus() # Note, we send None chatstate to preserve current self.parent_win.redraw_tab(self) @@ -635,22 +661,28 @@ class ChatControlBase(MessageControl): return True def on_conversation_vadjustment_value_changed(self, widget): - if not self.nb_unread: - return if self.resource: jid = self.contact.get_full_jid() else: jid = self.contact.jid + type_ = self.type_id + if type_ == message_control.TYPE_GC: + type_ = 'gc_msg' + if not len(gajim.events.get_events(self.account, jid, ['printed_' + type_, + type_])): + return if self.conv_textview.at_the_end() and \ self.parent_win.get_active_control() == self and \ self.parent_win.window.is_active(): - #we are at the end - self.nb_unread = self.get_specific_unread() - self.parent_win.redraw_tab(self) - self.parent_win.show_title() - if gajim.interface.systray_capabilities: - gajim.interface.systray.remove_jid(jid, self.account, - self.type_id) + # we are at the end + type_ = self.type_id + if type_ == message_control.TYPE_GC: + type_ = 'gc_msg' + if not gajim.events.remove_events(self.account, self.get_full_jid(), + types = ['printed_' + type_, type_]): + # There were events to remove + self.parent_win.redraw_tab(self) + self.parent_win.show_title() def sent_messages_scroll(self, direction, conv_buf): size = len(self.sent_history) @@ -1140,7 +1172,12 @@ class ChatControl(ChatControlBase): def get_tab_label(self, chatstate): unread = '' - num_unread = self.nb_unread + if self.resource: + jid = self.contact.get_full_jid() + else: + jid = self.contact.jid + num_unread = len(gajim.events.get_events(self.account, jid, + ['printed_' + self.type_id, self.type_id])) if num_unread == 1 and not gajim.config.get('show_unread_tab_icon'): unread = '*' elif num_unread > 1: @@ -1183,7 +1220,12 @@ class ChatControl(ChatControlBase): return (label_str, color) def get_tab_image(self): - num_unread = self.nb_unread + if self.resource: + jid = self.contact.get_full_jid() + else: + jid = self.contact.jid + num_unread = len(gajim.events.get_events(self.account, jid, + ['printed_' + self.type_id, self.type_id])) # Set tab image (always 16x16); unread messages show the 'message' image tab_img = None @@ -1192,8 +1234,8 @@ class ChatControl(ChatControlBase): self.contact.jid, icon_name = 'message') tab_img = img_16['message'] else: - contact = gajim.contacts.get_contact_with_highest_priority(self.account, - self.contact.jid) + contact = gajim.contacts.get_contact_with_highest_priority( + self.account, self.contact.jid) if not contact or self.resource: # For transient contacts contact = self.contact @@ -1369,10 +1411,9 @@ class ChatControl(ChatControlBase): # Remove bigger avatar window if self.bigger_avatar_window: self.bigger_avatar_window.destroy() - # Clean up systray - if gajim.interface.systray_capabilities and self.nb_unread > 0: - gajim.interface.systray.remove_jid(self.contact.jid, self.account, - self.type_id) + # Clean events + gajim.events.remove_events(self.account, self.get_full_jid(), + types = ['printed_' + self.type_id, self.type_id]) # remove all register handlers on wigets, created by self.xml # to prevent circular references among objects for i in self.handlers.keys(): @@ -1474,14 +1515,11 @@ class ChatControl(ChatControlBase): if restore_how_many <= 0: return timeout = gajim.config.get('restore_timeout') # in minutes - # number of messages that are in queue and are already logged - pending_how_many = 0 # we want to avoid duplication - if gajim.awaiting_events[self.account].has_key(jid): - events = gajim.awaiting_events[self.account][jid] - for event in events: - if event[0] == 'chat': - pending_how_many += 1 + events = gajim.events.get_events(self.account, jid, ['chat']) + # number of messages that are in queue and are already logged, we want + # to avoid duplication + pending_how_many = len(events) rows = gajim.logger.get_last_conversation_lines(jid, restore_how_many, pending_how_many, timeout, self.account) @@ -1522,7 +1560,7 @@ class ChatControl(ChatControlBase): jid_with_resource = jid if self.resource: jid_with_resource += '/' + self.resource - l = gajim.awaiting_events[self.account][jid_with_resource] + events = gajim.events.get_events(self.account, jid_with_resource) # Is it a pm ? is_pm = False @@ -1530,15 +1568,12 @@ class ChatControl(ChatControlBase): control = gajim.interface.msg_win_mgr.get_control(room_jid, self.account) if control and control.type_id == message_control.TYPE_GC: is_pm = True - events_to_keep = [] # list of message ids which should be marked as read message_ids = [] - for event in l: - typ = event[0] - if typ != 'chat': - events_to_keep.append(event) + for event in events: + if event.type_ != 'chat': continue - data = event[1] + data = event.parameters kind = data[2] if kind == 'error': kind = 'info' @@ -1548,22 +1583,16 @@ class ChatControl(ChatControlBase): encrypted = data[4], subject = data[1]) if len(data) > 6 and isinstance(data[6], int): message_ids.append(data[6]) - # remove from gc nb_unread if it's pm or from roster - if is_pm: - control.nb_unread -= 1 - else: - gajim.interface.roster.nb_unread -= 1 if message_ids: gajim.logger.set_read_messages(message_ids) - if is_pm: - control.parent_win.show_title() - else: - gajim.interface.roster.show_title() - # Keep only non-messages events - if len(events_to_keep): - gajim.awaiting_events[self.account][jid_with_resource] = events_to_keep - else: - del gajim.awaiting_events[self.account][jid_with_resource] + gajim.events.remove_events(self.account, jid_with_resource, + types = ['chat']) + + self.parent_win.show_title() + self.parent_win.redraw_tab(self) + # redraw roster + gajim.interface.roster.show_title() + typ = 'chat' # Is it a normal chat or a pm ? # reset to status image in gc if it is a pm if is_pm: @@ -1573,8 +1602,6 @@ class ChatControl(ChatControlBase): gajim.interface.roster.draw_contact(jid, self.account) # Redraw parent too gajim.interface.roster.draw_parent_contact(jid, self.account) - if gajim.interface.systray_capabilities: - gajim.interface.systray.remove_jid(jid_with_resource, self.account, typ) if (self.contact.show == 'offline' or self.contact.show == 'error'): showOffline = gajim.config.get('showoffline') if not showOffline and typ == 'chat' and \ diff --git a/src/common/events.py b/src/common/events.py new file mode 100644 index 0000000000..bc190f6c4b --- /dev/null +++ b/src/common/events.py @@ -0,0 +1,230 @@ +## common/events.py +## +## Contributors for this file: +## - Yann Le Boulanger <asterix@lagaule.org> +## +## Copyright (C) 2006 Yann Le Boulanger <asterix@lagaule.org> +## Vincent Hanquez <tab@snarc.org> +## Nikos Kouremenos <nkour@jabber.org> +## Dimitur Kirov <dkirov@gmail.com> +## Travis Shirk <travis@pobox.com> +## Norman Rasmussen <norman@rasmussen.co.za> +## +## This program 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; version 2 only. +## +## This program 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. +## + +import time +import gajim + +class Event: + '''Information concerning each event''' + def __init__(self, type_, time_, parameters, show_in_roster = False, + show_in_systray = True): + ''' type_ in chat, normal, file-request, file-error, file-completed, + file-request-error, file-send-error, file-stopped, gc_msg, pm, + printed_chat, printed_gc_msg, printed_pm + parameters is (per type_): + chat, normal: [message, subject, kind, time, encrypted, resource, + msg_id] + where kind in error, incoming + file-*: file_props + gc_msg: None + printed_*: None + messages that are already printed in chat, but not read''' + self.type_ = type_ + self.time_ = time_ + self.parameters = parameters + self.show_in_roster = show_in_roster + self.show_in_systray = show_in_systray + +class Events: + '''Information concerning all events''' + def __init__(self): + self._events = {} # list of events {acct: {jid1: [E1, E2]}, } + + def change_account_name(self, old_name, new_name): + if self._events.has_key(old_name): + self._events[new_name] = self._events[old_name] + del self._events[old_name] + + def add_account(self, account): + self._events[account] = {} + + def get_accounts(self): + return self._events.keys() + + def remove_account(self, account): + del self._events[account] + + def create_event(self, type_, parameters, time_ = time.time(), + show_in_roster = False, show_in_systray = True): + return Event(type_, time_, parameters, show_in_roster, + show_in_systray) + + def add_event(self, account, jid, event): + # No such account before ? + if not self._events.has_key(account): + self._events[account] = {jid: [event]} + # no such jid before ? + elif not self._events[account].has_key(jid): + self._events[account][jid] = [event] + else: + self._events[account][jid].append(event) + if event.show_in_systray: + gajim.interface.systray.set_img() + + def remove_events(self, account, jid, event = None, types = []): + '''if event is not speficied, remove all events from this jid, + optionnaly only from given type + return True if no such event found''' + if not self._events.has_key(account): + return True + if not self._events[account].has_key(jid): + return True + if event: # remove only one event + if event in self._events[account][jid]: + if len(self._events[account][jid]) == 1: + del self._events[account][jid] + else: + self._events[account][jid].remove(event) + gajim.interface.systray.set_img() + return + else: + return True + if types: + new_list = [] # list of events to keep + for ev in self._events[account][jid]: + if ev.type_ not in types: + new_list.append(ev) + if len(new_list) == len(self._events[account][jid]): + return True + if new_list: + self._events[account][jid] = new_list + else: + del self._events[account][jid] + gajim.interface.systray.set_img() + return + # no event nor type given, remove them all + del self._events[account][jid] + gajim.interface.systray.set_img() + + def get_nb_events(self, types = []): + return self._get_nb_events(types = types) + + def get_events(self, account, jid = None, types = []): + '''if event is not speficied, remove all events from this jid, + optionnaly only from given type''' + if not self._events.has_key(account): + return [] + if not jid: + return self._events[account] + if not self._events[account].has_key(jid): + return [] + events_list = [] # list of events + for ev in self._events[account][jid]: + if not types or ev.type_ in types: + events_list.append(ev) + return events_list + + def get_first_event(self, account, jid = None, type_ = None): + '''Return the first event of type type_ if given''' + events_list = self.get_events(account, jid, type_) + # be sure it's bigger than latest event + first_event_time = time.time() + 1 + first_event = None + for event in events_list: + if event.time_ < first_event_time: + first_event_time = event.time_ + first_event = event + return first_event + + def _get_nb_events(self, account = None, jid = None, attribute = None, types = []): + '''return the number of events''' + nb = 0 + if account: + accounts = [account] + else: + accounts = self._events.keys() + for acct in accounts: + if not self._events.has_key(acct): + continue + if jid: + jids = [jid] + else: + jids = self._events[acct].keys() + for j in jids: + if not self._events[acct].has_key(j): + continue + for event in self._events[acct][j]: + if types and event.type_ not in types: + continue + if not attribute or \ + attribute == 'systray' and event.show_in_systray or \ + attribute == 'roster' and event.show_in_roster: + nb += 1 + return nb + + def _get_some_events(self, attribute): + '''attribute in systray, roster''' + events = {} + for account in self._events: + events[account] = {} + for jid in self._events[account]: + events[account][jid] = [] + for event in self._events[account][jid]: + if attribute == 'systray' and event.show_in_systray or \ + attribute == 'roster' and event.show_in_roster: + events[account][jid].append(event) + if not events[account][jid]: + del events[account][jid] + if not events[account]: + del events[account] + return events + + def _get_first_event_with_attribute(self, events): + '''get the first event + events is in the form {account1: {jid1: [ev1, ev2], },. }''' + # be sure it's bigger than latest event + first_event_time = time.time() + 1 + first_account = None + first_jid = None + first_event = None + for account in events: + for jid in events[account]: + for event in events[account][jid]: + if event.time_ < first_event_time: + first_event_time = event.time_ + first_account = account + first_jid = jid + first_event = event + return first_account, first_jid, first_event + + def get_nb_systray_events(self, types = []): + '''returns the number of events displayedin roster''' + return self._get_nb_events(attribute = 'systray', types = types) + + def get_systray_events(self): + '''return all events that must be displayed in systray: + {account1: {jid1: [ev1, ev2], },. }''' + return self._get_some_events('systray') + + def get_first_systray_event(self): + events = self.get_systray_events() + return self._get_first_event_with_attribute(events) + + def get_nb_roster_events(self, account = None, jid = None, types = []): + '''returns the number of events displayedin roster''' + return self._get_nb_events(attribute = 'roster', account = account, + jid = jid, types = types) + + def get_roster_events(self): + '''return all events that must be displayed in roster: + {account1: {jid1: [ev1, ev2], },. }''' + return self._get_some_events('roster') diff --git a/src/common/gajim.py b/src/common/gajim.py index edf1db2cb7..dc7794e6e3 100644 --- a/src/common/gajim.py +++ b/src/common/gajim.py @@ -23,6 +23,7 @@ import locale import config from contacts import Contacts +from events import Events interface = None # The actual interface (the gtk one for the moment) config = config.Config() @@ -98,14 +99,8 @@ groups = {} # list of groups newly_added = {} # list of contacts that has just signed in to_be_removed = {} # list of contacts that has just signed out -awaiting_events = {} # list of messages/FT reveived but not printed - # awaiting_events[jid] = (type, (data1, data2, ...)) - # if type in ('chat', 'normal'): data = (message, subject, kind, time, - # encrypted, resource) - # kind can be (incoming, error) - # if type in file-request, file-request-error, file-send-error, file-error, - # file-completed, file-stopped: - # data = file_props +events = Events() + nicks = {} # list of our nick names in each account # should we block 'contact signed in' notifications for this account? # this is only for the first 30 seconds after we change our show @@ -287,18 +282,6 @@ def get_hostname_from_account(account_name, use_srv = False): return config.get_per('accounts', account_name, 'custom_host') return config.get_per('accounts', account_name, 'hostname') -def get_first_event(account, jid, typ = None): - '''returns the first event of the given type from the awaiting_events queue''' - if not awaiting_events[account].has_key(jid): - return None - q = awaiting_events[account][jid] - if not typ: - return q[0] - for ev in q: - if ev[0] == typ: - return ev - return None - def get_notification_image_prefix(jid): '''returns the prefix for the notification images''' transport_name = get_transport_name_from_jid(jid) diff --git a/src/common/helpers.py b/src/common/helpers.py index edccad675e..3ff4b4978d 100644 --- a/src/common/helpers.py +++ b/src/common/helpers.py @@ -513,9 +513,9 @@ def get_global_status(): def get_icon_name_to_show(contact, account = None): '''Get the icon name to show in online, away, requested, ...''' - if account and gajim.awaiting_events[account].has_key(contact.jid): + if account and gajim.events.get_nb_roster_events(account, contact.jid): return 'message' - if account and gajim.awaiting_events[account].has_key( + if account and gajim.events.get_nb_roster_events(account, contact.get_full_jid()): return 'message' if contact.jid.find('@') <= 0: # if not '@' or '@' starts the jid ==> agent @@ -772,3 +772,23 @@ def allow_sound_notification(sound_event, advanced_notif_num = None): if gajim.config.get_per('soundevents', sound_event, 'enabled'): return True return False + +def get_chat_control(account, contact): + full_jid_with_resource = contact.jid + if contact.resource: + full_jid_with_resource += '/' + contact.resource + highest_contact = gajim.contacts.get_contact_with_highest_priority( + account, contact.jid) + # Look for a chat control that has the given resource, or default to + # one without resource + ctrl = gajim.interface.msg_win_mgr.get_control(full_jid_with_resource, + account) + if ctrl: + return ctrl + elif not highest_contact or not highest_contact.resource: + # unknow contact or offline message + return gajim.interface.msg_win_mgr.get_control(contact.jid, account) + elif highest_contact and contact.resource != \ + highest_contact.resource: + return None + return gajim.interface.msg_win_mgr.get_control(contact.jid, account) diff --git a/src/config.py b/src/config.py index 93c8c6716a..70692307f6 100644 --- a/src/config.py +++ b/src/config.py @@ -1213,7 +1213,7 @@ class AccountModificationWindow: _('You are currently connected to the server'), _('To change the account name, you must be disconnected.')) return - if len(gajim.awaiting_events[self.account]): + if len(gajim.events.get_events(self.account)): dialogs.ErrorDialog(_('Unread events'), _('To change the account name, you must read all pending ' 'events.')) @@ -1322,7 +1322,6 @@ class AccountModificationWindow: if name != self.account: #update variables gajim.interface.instances[name] = gajim.interface.instances[self.account] - gajim.awaiting_events[name] = gajim.awaiting_events[self.account] gajim.nicks[name] = gajim.nicks[self.account] gajim.block_signed_in_notifications[name] = \ gajim.block_signed_in_notifications[self.account] @@ -1339,23 +1338,17 @@ class AccountModificationWindow: gajim.status_before_autoaway[self.account] gajim.contacts.change_account_name(self.account, name) + gajim.events.change_account_name(self.account, name) - #upgrade account variable in opened windows + # upgrade account variable in opened windows for kind in ('infos', 'disco', 'chats', 'gc', 'gc_config'): for j in gajim.interface.instances[name][kind]: gajim.interface.instances[name][kind][j].account = name - #upgrade account in systray - if gajim.interface.systray_capabilities: - for list in gajim.interface.systray.jids: - if list[0] == self.account: - list[0] = name - # ServiceCache object keep old property account if hasattr(gajim.connections[self.account], 'services_cache'): gajim.connections[self.account].services_cache.account = name del gajim.interface.instances[self.account] - del gajim.awaiting_events[self.account] del gajim.nicks[self.account] del gajim.block_signed_in_notifications[self.account] del gajim.groups[self.account] @@ -1780,7 +1773,7 @@ class AccountsWindow: if not iter: return account = model.get_value(iter, 0).decode('utf-8') - if len(gajim.awaiting_events[account]): + if len(gajim.events.get_events(account)): dialogs.ErrorDialog(_('Unread events'), _('Read all pending events before removing this account.')) return @@ -2285,7 +2278,6 @@ class RemoveAccountWindow: gajim.config.del_per('accounts', self.account) gajim.interface.save_config() del gajim.interface.instances[self.account] - del gajim.awaiting_events[self.account] del gajim.nicks[self.account] del gajim.block_signed_in_notifications[self.account] del gajim.groups[self.account] @@ -2911,7 +2903,6 @@ _('You can set advanced account options by pressing Advanced button, or later by # update variables gajim.interface.instances[self.account] = {'infos': {}, 'disco': {}, 'chats': {}, 'gc': {}, 'gc_config': {}} - gajim.awaiting_events[self.account] = {} gajim.connections[self.account].connected = 0 gajim.groups[self.account] = {} gajim.contacts.add_account(self.account) diff --git a/src/filetransfers_window.py b/src/filetransfers_window.py index fbd522cadc..29b2477115 100644 --- a/src/filetransfers_window.py +++ b/src/filetransfers_window.py @@ -445,12 +445,11 @@ _('Connection with peer cannot be established.')) jid = gajim.get_jid_without_resource(other) else: # It's a Contact instance jid = other.jid - if gajim.awaiting_events[account].has_key(jid): - for event in gajim.awaiting_events[account][jid]: - if event[0] in ('file-error', 'file-completed', - 'file-request-error', 'file-send-error', 'file-stopped') and \ - event[1]['sid'] == file_props['sid']: - gajim.interface.remove_event(account, jid, event) + for ev_type in ('file-error', 'file-completed', 'file-request-error', + 'file-send-error', 'file-stopped'): + for event in gajim.events.get_events(account, jid, [ev_type]): + if event.parameters[1]['sid'] == file_props['sid']: + gajim.events.remove_events(account, jid, event) del(self.files_props[sid[0]][sid[1:]]) del(file_props) diff --git a/src/gajim.py b/src/gajim.py index 978bc3fa61..d1f7fa7c94 100755 --- a/src/gajim.py +++ b/src/gajim.py @@ -389,7 +389,7 @@ class Interface: else: contact1 = gajim.contacts.get_first_contact_from_jid(account, ji) if not contact1: - # presence of another resource of out jid + # presence of another resource of our jid if resource == gajim.connections[account].server_resource: return contact1 = gajim.contacts.create_contact(jid = ji, @@ -570,8 +570,8 @@ class Interface: # Is it a first or next message received ? first = False - if not chat_control and not gajim.awaiting_events[account].has_key( - jid_of_control): + if not chat_control and not gajim.events.get_events(account, + jid_of_control, ['chat']): # It's a first message and not a Private Message first = True @@ -973,7 +973,7 @@ class Interface: c = contacts[0] self.roster.remove_contact(c, account) gajim.contacts.remove_jid(account, jid) - if gajim.awaiting_events[account].has_key(c.jid): + if gajim.events.get_events(account, c.jid): keyID = '' attached_keys = gajim.config.get_per('accounts', account, 'attached_gpg_keys').split() @@ -1108,60 +1108,48 @@ class Interface: path_to_bw_file = path_to_file + '_notif_size_bw.png' bwbuf.save(path_to_bw_file, 'png') - def add_event(self, account, jid, typ, args): - '''add an event to the awaiting_events var''' - # We add it to the awaiting_events queue + def add_event(self, account, jid, type_, args): + '''add an event to the gajim.events var''' + # We add it to the gajim.events queue # Do we have a queue? jid = gajim.get_jid_without_resource(jid) - qs = gajim.awaiting_events[account] - no_queue = False - if not qs.has_key(jid): - no_queue = True - qs[jid] = [] - qs[jid].append((typ, args)) - self.roster.nb_unread += 1 + no_queue = len(gajim.events.get_events(account, jid)) == 0 + event_type = None + # type_ can be gc-invitation file-send-error file-error file-request-error + # file-request file-completed file-stopped + # event_type can be in advancedNotificationWindow.events_list + event_types = {'file-request': 'ft_request', + 'file-completed': 'ft_finished'} + if type_ in event_types: + event_type = event_types[type_] + show_in_roster = notify.get_show_in_roster(event_type, account, jid) + show_in_systray = notify.get_show_in_systray(event_type, account, jid) + event = gajim.events.create_event(type_, args, + show_in_roster = show_in_roster, + show_in_systray = show_in_systray) + gajim.events.add_event(account, jid, event) self.roster.show_title() if no_queue: # We didn't have a queue: we change icons self.roster.draw_contact(jid, account) - if self.systray_capabilities: - self.systray.add_jid(jid, account, typ) - def redraw_roster_systray(self, account, jid, typ = None): - self.roster.nb_unread -= 1 - self.roster.show_title() - self.roster.draw_contact(jid, account) - if self.systray_capabilities: - self.systray.remove_jid(jid, account, typ) - - def remove_first_event(self, account, jid, typ = None): - qs = gajim.awaiting_events[account] - event = gajim.get_first_event(account, jid, typ) - qs[jid].remove(event) - # Is it the last event? - if not len(qs[jid]): - del qs[jid] - if not gajim.config.get('showoffline'): - contact = gajim.contacts.get_contact_with_highest_priority(account, - jid) - if contact: - self.roster.really_remove_contact(contact, account) - self.redraw_roster_systray(account, jid, typ) + 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): - qs = gajim.awaiting_events[account] - if not event in qs[jid]: + if gajim.events.remove_events(account, jid, event): + # No such event found return - qs[jid].remove(event) - # Is it the last event? - if not len(qs[jid]): - del qs[jid] + # no other event? + if not len(gajim.events.get_events(account, jid)): if not gajim.config.get('showoffline'): contact = gajim.contacts.get_contact_with_highest_priority(account, jid) - if contact: + if contact: self.roster.really_remove_contact(contact, account) - self.redraw_roster_systray(account, jid, event[0]) + self.roster.show_title() + self.roster.draw_contact(jid, account) def handle_event_file_request_error(self, account, array): jid = array[0] @@ -1187,7 +1175,7 @@ class Interface: if helpers.allow_showing_notification(account): # check if we should be notified img = os.path.join(gajim.DATA_DIR, 'pixmaps', 'events', 'ft_error.png') - + path = gtkgui_helpers.get_path_to_generic_or_avatar(img) event_type = _('File Transfer Error') notify.popup(event_type, jid, account, msg_type, path, @@ -1210,7 +1198,8 @@ class Interface: if helpers.allow_showing_notification(account): img = os.path.join(gajim.DATA_DIR, 'pixmaps', 'events', 'ft_request.png') - txt = _('%s wants to send you a file.') % gajim.get_name_from_jid(account, jid) + txt = _('%s wants to send you a file.') % gajim.get_name_from_jid( + account, jid) path = gtkgui_helpers.get_path_to_generic_or_avatar(img) event_type = _('File Transfer Request') notify.popup(event_type, jid, account, 'file-request', @@ -1219,7 +1208,7 @@ class Interface: def handle_event_file_progress(self, account, file_props): self.instances['file_transfers'].set_progress(file_props['type'], file_props['sid'], file_props['received-len']) - + def handle_event_file_rcv_completed(self, account, file_props): ft = self.instances['file_transfers'] if file_props['error'] == 0: @@ -1245,13 +1234,14 @@ class Interface: msg_type = '' event_type = '' - if file_props['error'] == 0 and gajim.config.get('notify_on_file_complete'): + if file_props['error'] == 0 and gajim.config.get( + 'notify_on_file_complete'): msg_type = 'file-completed' event_type = _('File Transfer Completed') elif file_props['error'] == -1: msg_type = 'file-stopped' event_type = _('File Transfer Stopped') - + if event_type == '': # FIXME: ugly workaround (this can happen Gajim sent, Gaim recvs) # this should never happen but it does. see process_result() in socks5.py @@ -1261,7 +1251,7 @@ class Interface: if msg_type: self.add_event(account, jid, msg_type, file_props) - + if file_props is not None: if file_props['type'] == 'r': # get the name of the sender, as it is in the roster @@ -1712,14 +1702,14 @@ class Interface: err_str) sys.exit() - def handle_event(self, account, jid, typ): + def handle_event(self, account, jid, type_): w = None fjid = jid resource = gajim.get_resource_from_jid(jid) jid = gajim.get_jid_without_resource(jid) - if typ == message_control.TYPE_GC: + if type_ in ('printed_gc_msg', 'gc_msg'): w = self.msg_win_mgr.get_window(jid, account) - elif typ == message_control.TYPE_CHAT: + elif type_ in ('printed_chat', 'chat'): if self.msg_win_mgr.has_window(fjid, account): w = self.msg_win_mgr.get_window(fjid, account) else: @@ -1729,30 +1719,30 @@ class Interface: self.roster.new_chat(contact, account, resource = resource) w = self.msg_win_mgr.get_window(fjid, account) gajim.last_message_time[account][jid] = 0 # long time ago - elif typ == message_control.TYPE_PM: + elif type_ in ('printed_pm', 'pm'): if self.msg_win_mgr.has_window(fjid, account): w = self.msg_win_mgr.get_window(fjid, account) else: room_jid = jid nick = resource gc_contact = gajim.contacts.get_gc_contact(account, room_jid, - nick) + nick) if gc_contact: show = gc_contact.show else: show = 'offline' - gc_contact = gajim.contacts.create_gc_contact(room_jid = room_jid, - name = nick, show = show) + gc_contact = gajim.contacts.create_gc_contact( + room_jid = room_jid, name = nick, show = show) c = gajim.contacts.contact_from_gc_contact(gc_contact) self.roster.new_chat(c, account, private_chat = True) w = self.msg_win_mgr.get_window(fjid, account) - elif typ in ('normal', 'file-request', 'file-request-error', - 'file-send-error', 'file-error', 'file-stopped', 'file-completed'): + elif type_ in ('normal', 'file-request', 'file-request-error', + 'file-send-error', 'file-error', 'file-stopped', 'file-completed'): # Get the first single message event - ev = gajim.get_first_event(account, jid, typ) + event = gajim.events.get_first_event(account, jid, type_) # Open the window - self.roster.open_event(account, jid, ev) - elif typ == 'gmail': + self.roster.open_event(account, jid, event) + elif type_ == 'gmail': if gajim.config.get_per('accounts', account, 'savepass'): url = ('http://www.google.com/accounts/ServiceLoginAuth?service=mail&Email=%s&Passwd=%s&continue=https://mail.google.com/mail') %\ (urllib.quote(gajim.config.get_per('accounts', account, 'name')), @@ -1760,12 +1750,12 @@ class Interface: else: url = ('http://mail.google.com/') helpers.launch_browser_mailer('url', url) - elif typ == 'gc-invitation': - ev = gajim.get_first_event(account, jid, typ) - data = ev[1] + elif type_ == 'gc-invitation': + event = gajim.events.get_first_event(account, jid, type_) + data = event.parameters dialogs.InvitationReceivedDialog(account, data[0], jid, data[2], data[1]) - self.remove_first_event(account, jid, typ) + gajim.events.remove_events(account, jid, event) if w: w.set_active_tab(fjid, account) w.window.present() @@ -1860,7 +1850,6 @@ class Interface: gajim.automatic_rooms[a] = {} gajim.newly_added[a] = [] gajim.to_be_removed[a] = [] - gajim.awaiting_events[a] = {} gajim.nicks[a] = gajim.config.get_per('accounts', a, 'name') gajim.block_signed_in_notifications[a] = True gajim.sleeper_state[a] = 0 diff --git a/src/groupchat_control.py b/src/groupchat_control.py index 0817faca5e..5ad6c9c4ed 100644 --- a/src/groupchat_control.py +++ b/src/groupchat_control.py @@ -446,10 +446,7 @@ class GroupchatControl(ChatControlBase): def on_private_message(self, nick, msg, tim): # Do we have a queue? fjid = self.room_jid + '/' + nick - qs = gajim.awaiting_events[self.account] - no_queue = True - if qs.has_key(fjid): - no_queue = False + no_queue = len(gajim.events.get_events(self.account, fjid)) == 0 # We print if window is opened pm_control = gajim.interface.msg_win_mgr.get_control(fjid, self.account) @@ -457,9 +454,9 @@ class GroupchatControl(ChatControlBase): pm_control.print_conversation(msg, tim = tim) return - if no_queue: - qs[fjid] = [] - qs[fjid].append(('chat', (msg, '', 'incoming', tim, False, ''))) + event = gajim.events.create_event('chat', (msg, '', 'incoming', tim, + False, '', None)) + gajim.events.add_event(self.account, fjid, event) autopopup = gajim.config.get('autopopup') autopopupaway = gajim.config.get('autopopupaway') @@ -474,8 +471,6 @@ class GroupchatControl(ChatControlBase): self.room_jid, icon_name = 'message') image = state_images['message'] model[iter][C_IMG] = image - if gajim.interface.systray_capabilities: - gajim.interface.systray.add_jid(fjid, self.account, 'pm') self.parent_win.show_title() else: self._start_private_message(nick) @@ -697,7 +692,7 @@ class GroupchatControl(ChatControlBase): model = self.list_treeview.get_model() gc_contact = gajim.contacts.get_gc_contact(self.account, self.room_jid, nick) state_images = gajim.interface.roster.jabber_state_images['16'] - if gajim.awaiting_events[self.account].has_key(self.room_jid + '/' + nick): + if len(gajim.events.get_events(self.account, self.room_jid + '/' + nick)): image = state_images['message'] else: image = state_images[gc_contact.show] @@ -801,7 +796,8 @@ class GroupchatControl(ChatControlBase): os.rename(old_file, files[old_file]) self.print_conversation(s, 'info') - if not gajim.awaiting_events[self.account].has_key(self.room_jid + '/' + nick): + if len(gajim.events.get_events(self.account, + self.room_jid + '/' + nick)) == 0: self.remove_contact(nick) else: c = gajim.contacts.get_gc_contact(self.account, self.room_jid, nick) @@ -1291,9 +1287,8 @@ class GroupchatControl(ChatControlBase): nb = 0 for nick in gajim.contacts.get_nick_list(self.account, self.room_jid): fjid = self.room_jid + '/' + nick - if gajim.awaiting_events[self.account].has_key(fjid): - # gc can only have messages as event - nb += len(gajim.awaiting_events[self.account][fjid]) + nb += len(gajim.events.get_events(self.account, fjid)) + # gc can only have messages as event return nb def _on_change_subject_menuitem_activate(self, widget): diff --git a/src/message_control.py b/src/message_control.py index 728c609227..1c1b0aa50c 100644 --- a/src/message_control.py +++ b/src/message_control.py @@ -39,7 +39,6 @@ class MessageControl: self.account = account self.hide_chat_buttons_always = False self.hide_chat_buttons_current = False - self.nb_unread = 0 self.resource = resource gajim.last_message_time[self.account][self.get_full_jid()] = 0 @@ -117,10 +116,7 @@ class MessageControl: pass def get_specific_unread(self): - n = 0 - if gajim.awaiting_events[self.account].has_key(self.contact.jid): - n = len(gajim.awaiting_events[self.account][self.contact.jid]) - return n + return len(gajim.events.get_events(self.account, self.contact.jid)) def send_message(self, message, keyID = '', type = 'chat', chatstate = None, msg_id = None, composing_jep = None, resource = None, diff --git a/src/message_window.py b/src/message_window.py index 61cf4b7137..f190956c8a 100644 --- a/src/message_window.py +++ b/src/message_window.py @@ -224,7 +224,7 @@ class MessageWindow: gajim.config.get('notify_on_all_muc_messages') and not \ ctrl.attention_flag: continue - unread += ctrl.nb_unread + unread += ctrl.get_nb_unread() unread_str = '' if unread > 1: @@ -280,9 +280,8 @@ class MessageWindow: ctrl.shutdown() # Update external state - if gajim.interface.systray_capabilities: - gajim.interface.systray.remove_jid(ctrl.get_full_jid(), ctrl.account, - ctrl.type_id) + gajim.events.remove_events(ctrl.account, ctrl.get_full_jid, + types = ['printed_msg', 'chat', 'gc_msg']) del gajim.last_message_time[ctrl.account][ctrl.get_full_jid()] self.disconnect_tab_dnd(ctrl.widget) @@ -432,7 +431,7 @@ class MessageWindow: if ind < 0: ind = self.notebook.get_n_pages() - 1 ctrl = self.get_control(ind, None) - if ctrl.nb_unread > 0: + if ctrl.get_nb_unread() > 0: found = True break # found elif gajim.config.get('ctrl_tab_go_to_next_composing') : # Search for a composing contact diff --git a/src/notify.py b/src/notify.py index 4f7818a02f..e4578e072c 100644 --- a/src/notify.py +++ b/src/notify.py @@ -32,7 +32,37 @@ if dbus_support.supported: import dbus.glib import dbus.service +def get_show_in_roster(event, account, contact): + '''Return True if this event must be shown in roster, else False''' + num = get_advanced_notification(event, account, contact) + if num != None: + if gajim.config.get_per('notifications', str(num), 'roster') == 'yes': + return True + if gajim.config.get_per('notifications', str(num), 'roster') == 'no': + return False + if event == 'message_received': + chat_control = helpers.get_chat_control(account, contact) + if not chat_control: + return True + elif event == 'ft_request': + return True + return False + +def get_show_in_systray(event, account, contact): + '''Return True if this event must be shown in roster, else False''' + num = get_advanced_notification(event, account, contact) + if num != None: + if gajim.config.get_per('notifications', str(num), 'systray') == 'yes': + return True + if gajim.config.get_per('notifications', str(num), 'systray') == 'no': + return False + if event in ('message_received', 'ft_request', 'gc_msg_highlight', + 'ft_request'): + return True + return False + def get_advanced_notification(event, account, contact): + '''Returns the number of the first advanced notification or None''' num = 0 notif = gajim.config.get_per('notifications', str(num)) while notif: @@ -68,26 +98,7 @@ def get_advanced_notification(event, account, contact): if tab_opened == 'both': tab_opened_ok = True else: - chat_control = False - full_jid_with_resource = contact.jid - if contact.resource: - full_jid_with_resource += '/' + contact.resource - highest_contact = gajim.contacts.get_contact_with_highest_priority( - account, contact.jid) - # Look for a chat control that has the given resource, or default to - # one without resource - if gajim.interface.msg_win_mgr.get_control(full_jid_with_resource, - account): - chat_control = True - elif not highest_contact or not highest_contact.resource: - # unknow contact or offline message - if gajim.interface.msg_win_mgr.get_control(contact.jid, account): - chat_control = True - elif highest_contact and contact.resource != \ - highest_contact.resource: - chat_control = False - elif gajim.interface.msg_win_mgr.get_control(contact.jid, account): - chat_control = True + chat_control = helper.get_chat_control(account, contact) if (chat_control and tab_opened == 'yes') or (not chat_control and \ tab_opened == 'no'): tab_opened_ok = True diff --git a/src/remote_control.py b/src/remote_control.py index 64deb55b04..802bf64c8f 100644 --- a/src/remote_control.py +++ b/src/remote_control.py @@ -596,7 +596,7 @@ class SignalObject(DbusPrototype): return contact_dict def get_unread_msgs_number(self, *args): - return str(gajim.interface.roster.nb_unread) + return str(gajim.events.get_nb_events) def start_chat(self, *args): [account] = self._get_real_arguments(args, 1) diff --git a/src/roster_window.py b/src/roster_window.py index 0c3391f0d9..6b1330d74a 100644 --- a/src/roster_window.py +++ b/src/roster_window.py @@ -29,6 +29,7 @@ import gtkgui_helpers import cell_renderer_image import tooltips import message_control +import notify from common import gajim from common import helpers @@ -263,7 +264,7 @@ class RosterWindow: if big_brother_jid != jid or big_brother_account != account: # We are adding a child contact if contact.show in ('offline', 'error') and \ - not showOffline and not gajim.awaiting_events[account].has_key(jid): + not showOffline and len(gajim.events.get_events(account, jid)) == 0: return parent_iters = self.get_contact_iter(big_brother_jid, big_brother_account) @@ -281,7 +282,7 @@ class RosterWindow: if (contact.show in ('offline', 'error') or hide) and \ not showOffline and (not _('Transports') in contact.groups or \ gajim.connections[account].connected < 2) and \ - not gajim.awaiting_events[account].has_key(jid) and \ + len(gajim.events.get_events(account, jid)) == 0 and \ not _('Not in Roster') in contact.groups: return @@ -355,7 +356,7 @@ class RosterWindow: return showOffline = gajim.config.get('showoffline') if (contact.show in ('offline', 'error')) and not showOffline and \ - not gajim.awaiting_events[account].has_key(jid): + len(gajim.events.get_events(account, jid)) == 0: return model = self.tree.get_model() @@ -396,7 +397,7 @@ class RosterWindow: if (contact.show in ('offline', 'error') or hide) and \ not showOffline and (not _('Transports') in contact.groups or \ gajim.connections[account].connected < 2) and \ - not gajim.awaiting_events[account].has_key(contact.jid): + len(gajim.events.get_events(account, contact.jid)) == 0: self.remove_contact(contact, account) else: self.draw_contact(contact.jid, account) @@ -506,7 +507,7 @@ class RosterWindow: iter = iters[0] # choose the icon with the first iter icon_name = helpers.get_icon_name_to_show(contact, account) - # look if anotherresource has awaiting events + # look if another resource has awaiting events for c in contact_instances: c_icon_name = helpers.get_icon_name_to_show(c, account) if c_icon_name == 'message': @@ -530,7 +531,7 @@ class RosterWindow: # a child has awaiting messages ? child_jid = model[child_iter][C_JID].decode('utf-8') child_account = model[child_iter][C_ACCOUNT].decode('utf-8') - if gajim.awaiting_events[child_account].has_key(child_jid): + if len(gajim.events.get_events(child_account, child_jid)): icon_name = 'message' break child_iter = model.iter_next(child_iter) @@ -1061,7 +1062,7 @@ class RosterWindow: contact.show = show contact.status = status if show in ('offline', 'error') and \ - not gajim.awaiting_events[account].has_key(contact.jid): + len(gajim.events.get_events(account, contact.jid)) == 0: if len(contact_instances) > 1: # if multiple resources gajim.contacts.remove_contact(account, contact) @@ -2077,7 +2078,7 @@ _('If "%s" accepts this request you will know his or her status.') % jid) contact.sub = 'from' gajim.contacts.add_contact(account, contact) self.add_contact_to_roster(contact.jid, account) - elif gajim.awaiting_events[account].has_key(contact.jid): + elif len(gajim.events.get_events(account, contact.jid)): need_readd = True elif gajim.interface.msg_win_mgr.has_window(contact.jid, account): if _('Not in Roster') in contact.groups: @@ -2397,7 +2398,7 @@ _('If "%s" accepts this request you will know his or her status.') % jid) mw.new_tab(chat_control) - if gajim.awaiting_events[account].has_key(fjid): + if len(gajim.events.get_events(account, fjid)): # We call this here to avoid race conditions with widget validation chat_control.read_queue() @@ -2493,10 +2494,7 @@ _('If "%s" accepts this request you will know his or her status.') % jid) resource_for_chat = None # Do we have a queue? - qs = gajim.awaiting_events[account] - no_queue = True - if qs.has_key(fjid): - no_queue = False + no_queue = len(gajim.events.get_events(account, fjid)) == 0 popup = helpers.allow_popup_window(account, advanced_notif_num) @@ -2518,14 +2516,17 @@ _('If "%s" accepts this request you will know his or her status.') % jid) return # We save it in a queue - if no_queue: - qs[fjid] = [] - kind = 'chat' + type_ = 'chat' if msg_type == 'normal': - kind = 'normal' - qs[fjid].append((kind, (msg, subject, msg_type, tim, encrypted, - resource, msg_id))) - self.nb_unread += 1 + type_ = 'normal' + show_in_roster = notify.get_show_in_roster('message_received', account, + contact) + show_in_systray = notify.get_show_in_systray('message_received', account, + contact) + event = gajim.events.create_event(type_, (msg, subject, msg_type, tim, + encrypted, resource, msg_id), show_in_roster = show_in_roster, + show_in_systray = show_in_systray) + gajim.events.add_event(account, fjid, event) if popup: if not ctrl: self.new_chat(contact, account, resource = resource_for_chat) @@ -2555,8 +2556,6 @@ _('If "%s" accepts this request you will know his or her status.') % jid) self.tree.expand_row(path[0:2], False) self.tree.scroll_to_cell(path) self.tree.set_cursor(path) - if gajim.interface.systray_capabilities: - gajim.interface.systray.add_jid(fjid, account, kind, advanced_notif_num) def on_preferences_menuitem_activate(self, widget): if gajim.interface.instances.has_key('preferences'): @@ -2721,14 +2720,14 @@ _('If "%s" accepts this request you will know his or her status.') % jid) # check if we have unread or recent mesages unread = False recent = False - if self.nb_unread > 0: + if gajim.events.get_nb_events() > 0: unread = True for win in gajim.interface.msg_win_mgr.windows(): unrd = 0 for ctrl in win.controls(): if ctrl.type_id == message_control.TYPE_GC: if gajim.config.get('notify_on_all_muc_messages'): - unrd += ctrl.nb_unread + unrd += ctrl.get_nb_unread() else: if ctrl.attention_flag: unrd += 1 @@ -2765,33 +2764,30 @@ _('If "%s" accepts this request you will know his or her status.') % jid) def open_event(self, account, jid, event): '''If an event was handled, return True, else return False''' - if not event: - return False - typ = event[0] - data = event[1] + data = event.parameters ft = gajim.interface.instances['file_transfers'] - if typ == 'normal': + if event.type_ == 'normal': dialogs.SingleMessageWindow(account, jid, action = 'receive', from_whom = jid, subject = data[1], message = data[0], resource = data[5]) - gajim.interface.remove_first_event(account, jid, typ) + gajim.interface.remove_first_event(account, jid, event.type_) return True - elif typ == 'file-request': + elif event.type_ == 'file-request': contact = gajim.contacts.get_contact_with_highest_priority(account, jid) - gajim.interface.remove_first_event(account, jid, typ) + gajim.interface.remove_first_event(account, jid, event.type_) ft.show_file_request(account, contact, data) return True - elif typ in ('file-request-error', 'file-send-error'): - gajim.interface.remove_first_event(account, jid, typ) + elif event.type_ in ('file-request-error', 'file-send-error'): + gajim.interface.remove_first_event(account, jid, event.type_) ft.show_send_error(data) return True - elif typ in ('file-error', 'file-stopped'): - gajim.interface.remove_first_event(account, jid, typ) + elif event.type_ in ('file-error', 'file-stopped'): + gajim.interface.remove_first_event(account, jid, event.type_) ft.show_stopped(jid, data) return True - elif typ == 'file-completed': - gajim.interface.remove_first_event(account, jid, typ) + elif event.type_ == 'file-completed': + gajim.interface.remove_first_event(account, jid, event.type_) ft.show_completed(jid, data) return True return False @@ -2825,12 +2821,12 @@ _('If "%s" accepts this request you will know his or her status.') % jid) else: self.tree.expand_row(path, False) else: - first_ev = gajim.get_first_event(account, jid) + first_ev = gajim.events.get_first_event(account, jid) if not first_ev: # look in other resources for c in gajim.contacts.get_contact(account, jid): fjid = c.get_full_jid() - first_ev = gajim.get_first_event(account, fjid) + first_ev = gajim.events.get_first_event(account, fjid) if first_ev: resource = c.resource break @@ -2838,7 +2834,7 @@ _('If "%s" accepts this request you will know his or her status.') % jid) child_iter = model.iter_children(iter) while not first_ev and child_iter: child_jid = model[child_iter][C_JID].decode('utf-8') - first_ev = gajim.get_first_event(account, child_jid) + first_ev = gajim.events.get_first_event(account, child_jid) if first_ev: jid = child_jid else: @@ -3088,8 +3084,7 @@ _('If "%s" accepts this request you will know his or her status.') % jid) model[iter][1] = self.jabber_state_images['16'][model[iter][2]] iter = model.iter_next(iter) # Update the systray - if gajim.interface.systray_enabled: - gajim.interface.systray.set_img() + gajim.interface.systray.set_img() for win in gajim.interface.msg_win_mgr.windows(): for ctrl in win.controls(): @@ -3565,13 +3560,14 @@ _('If "%s" accepts this request you will know his or her status.') % jid) change_title_allowed = gajim.config.get('change_roster_title') if change_title_allowed: start = '' - if self.nb_unread > 1: - start = '[' + str(self.nb_unread) + '] ' - elif self.nb_unread == 1: + nb_unread = gajim.events.get_nb_events() + if nb_unread > 1: + start = '[' + str(nb_unread) + '] ' + elif nb_unread == 1: start = '* ' self.window.set_title(start + 'Gajim') - gtkgui_helpers.set_unset_urgency_hint(self.window, self.nb_unread) + gtkgui_helpers.set_unset_urgency_hint(self.window, nb_unread) def iter_is_separator(self, model, iter): if model[iter][0] == 'SEPARATOR': @@ -3640,7 +3636,6 @@ _('If "%s" accepts this request you will know his or her status.') % jid) self.transports_state_images = {'16': {}, '32': {}, 'opened': {}, 'closed': {}} - self.nb_unread = 0 # number of unread messages self.last_save_dir = None self.editing_path = None # path of row with cell in edit mode self.add_new_contact_handler_id = False diff --git a/src/systray.py b/src/systray.py index 2599224e02..6c5482d3c6 100644 --- a/src/systray.py +++ b/src/systray.py @@ -47,7 +47,6 @@ class Systray: for trayicon in GNU/Linux''' def __init__(self): - self.jids = [] # Contain things like [account, jid, type_of_msg] self.single_message_handler_id = None self.new_chat_handler_id = None self.t = None @@ -58,14 +57,10 @@ class Systray: self.xml.signal_autoconnect(self) self.popup_menus = [] - def set_img(self, advanced_notif_num = None): + def set_img(self): if not gajim.interface.systray_enabled: return - if advanced_notif_num: - if gajim.config.get_per('notifications', str(advanced_notif_num), - 'systray') == 'no': - return - if len(self.jids) > 0: + if gajim.events.get_nb_systray_events(): state = 'message' else: state = self.status @@ -75,19 +70,6 @@ class Systray: elif image.get_storage_type() == gtk.IMAGE_PIXBUF: self.img_tray.set_from_pixbuf(image.get_pixbuf()) - def add_jid(self, jid, account, typ, advanced_notif_num = None): - l = [account, jid, typ] - # We can keep several single message because we open them one by one - if not l in self.jids or typ == 'normal': - self.jids.append(l) - self.set_img(advanced_notif_num) - - def remove_jid(self, jid, account, typ): - l = [account, jid, typ] - if l in self.jids: - self.jids.remove(l) - self.set_img() - def change_status(self, global_status): ''' set tray image to 'global_status' ''' # change image and status, only if it is different @@ -244,8 +226,11 @@ class Systray: self.systray_context_menu.show_all() def on_show_all_events_menuitem_activate(self, widget): - for i in range(len(self.jids)): - self.handle_first_event() + events = gajim.events.get_systray_events() + for account in events: + for jid in events[account]: + for event in events[account][jid]: + gajim.interface.handle_event(account, jid, event.type_) def on_show_roster_menuitem_activate(self, widget): win = gajim.interface.roster.window @@ -262,7 +247,7 @@ class Systray: def on_left_click(self): win = gajim.interface.roster.window - if len(self.jids) == 0: + if len(gajim.events.get_systray_events()) == 0: # no pending events, so toggle visible/hidden for roster window if win.get_property('visible'): # visible in ANY virtual desktop? win.hide() # we hide it from VD that was visible in @@ -276,10 +261,8 @@ class Systray: self.handle_first_event() def handle_first_event(self): - account = self.jids[0][0] - jid = self.jids[0][1] - typ = self.jids[0][2] - gajim.interface.handle_event(account, jid, typ) + account, jid, event = gajim.events.get_first_systray_event() + gajim.interface.handle_event(account, jid, event.type_) def on_middle_click(self): '''middle click raises window to have complete focus (fe. get kbd events) diff --git a/src/systraywin32.py b/src/systraywin32.py index 54b8e0c1e9..c758247e01 100644 --- a/src/systraywin32.py +++ b/src/systraywin32.py @@ -245,49 +245,10 @@ class SystrayWin32(systray.Systray): elif lparam == win32con.WM_LBUTTONUP: # Left click self.on_left_click() - def add_jid(self, jid, account, typ): - systray.Systray.add_jid(self, jid, account, typ) - - nb = gajim.interface.roster.nb_unread - for acct in gajim.connections: - # in chat / groupchat windows - for kind in ('chats', 'gc'): - jids = gajim.interface.instances[acct][kind] - for jid in jids: - if jid != 'tabbed': - nb += jids[jid].nb_unread[jid] - - text = i18n.ngettext( - 'Gajim - %d unread message', - 'Gajim - %d unread messages', - nb, nb, nb) - - self.systray_winapi.notify_icon.set_tooltip(text) - - def remove_jid(self, jid, account, typ): - systray.Systray.remove_jid(self, jid, account, typ) - - nb = gajim.interface.roster.nb_unread - for acct in gajim.connections: - # in chat / groupchat windows - for kind in ('chats', 'gc'): - for jid in gajim.interface.instances[acct][kind]: - if jid != 'tabbed': - nb += gajim.interface.instances[acct][kind][jid].nb_unread[jid] - - if nb > 0: - text = i18n.ngettext( - 'Gajim - %d unread message', - 'Gajim - %d unread messages', - nb, nb, nb) - else: - text = 'Gajim' - self.systray_winapi.notify_icon.set_tooltip(text) - def set_img(self): self.tray_ico_imgs = self.load_icos() #FIXME: do not do this here # see gajim.interface.roster.reload_jabber_state_images() to merge - + if len(self.jids) > 0: state = 'message' else: @@ -295,12 +256,23 @@ class SystrayWin32(systray.Systray): hicon = self.tray_ico_imgs[state] if hicon is None: return - + self.systray_winapi.remove_notify_icon() self.systray_winapi.add_notify_icon(self.systray_context_menu, hicon, 'Gajim') self.systray_winapi.notify_icon.menu = self.systray_context_menu + nb = gajim.events.get_nb_systray_events() + + if nb > 0: + text = i18n.ngettext( + 'Gajim - %d unread message', + 'Gajim - %d unread messages', + nb, nb, nb) + else: + text = 'Gajim' + self.systray_winapi.notify_icon.set_tooltip(text) + def load_icos(self): '''load .ico files and return them to a dic of SHOW --> img_obj''' iconset = str(gajim.config.get('iconset')) diff --git a/src/tooltips.py b/src/tooltips.py index 6b95561f3e..53915df8ab 100644 --- a/src/tooltips.py +++ b/src/tooltips.py @@ -282,34 +282,14 @@ class NotificationAreaTooltip(BaseTooltip, StatusTable): self.table.set_property('column-spacing', 1) text, single_line = '', '' - unread_chat = gajim.interface.roster.nb_unread - unread_single_chat = 0 - unread_gc = 0 - unread_pm = 0 + unread_chat = gajim.events.get_nb_events(types = ['printed_chat', 'chat']) + unread_single_chat = gajim.events.get_nb_events(types = ['normal']) + unread_gc = gajim.events.get_nb_events(types = ['printed_gc_msg', + 'gc_msg']) + unread_pm = gajim.events.get_nb_events(types = ['printed_pm', 'pm']) accounts = self.get_accounts_info() - for acct in gajim.connections: - # Count unread chat messages - chat_t = message_control.TYPE_CHAT - for ctrl in gajim.interface.msg_win_mgr.get_controls(chat_t, acct): - unread_chat += ctrl.nb_unread - - # Count unread PM messages for which we have a control - chat_t = message_control.TYPE_PM - for ctrl in gajim.interface.msg_win_mgr.get_controls(chat_t, acct): - unread_pm += ctrl.nb_unread - - # we count unread gc/pm messages - chat_t = message_control.TYPE_GC - for ctrl in gajim.interface.msg_win_mgr.get_controls(chat_t, acct): - # These are PMs for which the PrivateChatControl has not yet been - # created - pm_msgs = ctrl.get_specific_unread() - unread_gc += ctrl.nb_unread - unread_gc -= pm_msgs - unread_pm += pm_msgs - if unread_chat or unread_single_chat or unread_gc or unread_pm: text = 'Gajim ' awaiting_events = unread_chat + unread_single_chat + unread_gc + unread_pm @@ -508,8 +488,9 @@ class RosterTooltip(NotificationAreaTooltip): properties = [] jid_markup = '<span weight="bold">' + prim_contact.jid + '</span>' properties.append((jid_markup, None)) + properties.append((_('Name: '), gtkgui_helpers.escape_for_pango_markup( - prim_contact.get_shown_name()))) + prim_contact.get_shown_name()))) if prim_contact.sub: properties.append(( _('Subscription: '), gtkgui_helpers.escape_for_pango_markup(helpers.get_uf_sub(prim_contact.sub)))) @@ -532,10 +513,11 @@ class RosterTooltip(NotificationAreaTooltip): contacts_dict[contact.priority].append(contact) else: contacts_dict[contact.priority] = [contact] - - if num_resources== 1 and contact.resource: - properties.append((_('Resource: '), gtkgui_helpers.escape_for_pango_markup( - contact.resource) + ' (' + unicode(contact.priority) + ')')) + + if num_resources == 1 and contact.resource: + properties.append((_('Resource: '), + gtkgui_helpers.escape_for_pango_markup(contact.resource) + ' (' + \ + unicode(contact.priority) + ')')) if num_resources > 1: properties.append((_('Status: '), ' ')) contact_keys = contacts_dict.keys() -- GitLab