| 1 | ## common/events.py |
|---|
| 2 | ## |
|---|
| 3 | ## Contributors for this file: |
|---|
| 4 | ## - Yann Le Boulanger <asterix@lagaule.org> |
|---|
| 5 | ## |
|---|
| 6 | ## Copyright (C) 2006 Yann Le Boulanger <asterix@lagaule.org> |
|---|
| 7 | ## Vincent Hanquez <tab@snarc.org> |
|---|
| 8 | ## Nikos Kouremenos <kourem@gmail.com> |
|---|
| 9 | ## Dimitur Kirov <dkirov@gmail.com> |
|---|
| 10 | ## Travis Shirk <travis@pobox.com> |
|---|
| 11 | ## Norman Rasmussen <norman@rasmussen.co.za> |
|---|
| 12 | ## |
|---|
| 13 | ## This program is free software; you can redistribute it and/or modify |
|---|
| 14 | ## it under the terms of the GNU General Public License as published |
|---|
| 15 | ## by the Free Software Foundation; version 2 only. |
|---|
| 16 | ## |
|---|
| 17 | ## This program is distributed in the hope that it will be useful, |
|---|
| 18 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 19 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 20 | ## GNU General Public License for more details. |
|---|
| 21 | ## |
|---|
| 22 | |
|---|
| 23 | import time |
|---|
| 24 | import gajim |
|---|
| 25 | |
|---|
| 26 | class Event: |
|---|
| 27 | '''Information concerning each event''' |
|---|
| 28 | def __init__(self, type_, time_, parameters, show_in_roster = False, |
|---|
| 29 | show_in_systray = True): |
|---|
| 30 | ''' type_ in chat, normal, file-request, file-error, file-completed, |
|---|
| 31 | file-request-error, file-send-error, file-stopped, gc_msg, pm, |
|---|
| 32 | printed_chat, printed_gc_msg, printed_pm |
|---|
| 33 | parameters is (per type_): |
|---|
| 34 | chat, normal: [message, subject, kind, time, encrypted, resource, |
|---|
| 35 | msg_id] |
|---|
| 36 | where kind in error, incoming |
|---|
| 37 | file-*: file_props |
|---|
| 38 | gc_msg: None |
|---|
| 39 | printed_*: None |
|---|
| 40 | messages that are already printed in chat, but not read''' |
|---|
| 41 | self.type_ = type_ |
|---|
| 42 | self.time_ = time_ |
|---|
| 43 | self.parameters = parameters |
|---|
| 44 | self.show_in_roster = show_in_roster |
|---|
| 45 | self.show_in_systray = show_in_systray |
|---|
| 46 | |
|---|
| 47 | class Events: |
|---|
| 48 | '''Information concerning all events''' |
|---|
| 49 | def __init__(self): |
|---|
| 50 | self._events = {} # list of events {acct: {jid1: [E1, E2]}, } |
|---|
| 51 | |
|---|
| 52 | def change_account_name(self, old_name, new_name): |
|---|
| 53 | if self._events.has_key(old_name): |
|---|
| 54 | self._events[new_name] = self._events[old_name] |
|---|
| 55 | del self._events[old_name] |
|---|
| 56 | |
|---|
| 57 | def add_account(self, account): |
|---|
| 58 | self._events[account] = {} |
|---|
| 59 | |
|---|
| 60 | def get_accounts(self): |
|---|
| 61 | return self._events.keys() |
|---|
| 62 | |
|---|
| 63 | def remove_account(self, account): |
|---|
| 64 | del self._events[account] |
|---|
| 65 | |
|---|
| 66 | def create_event(self, type_, parameters, time_ = time.time(), |
|---|
| 67 | show_in_roster = False, show_in_systray = True): |
|---|
| 68 | return Event(type_, time_, parameters, show_in_roster, |
|---|
| 69 | show_in_systray) |
|---|
| 70 | |
|---|
| 71 | def add_event(self, account, jid, event): |
|---|
| 72 | # No such account before ? |
|---|
| 73 | if not self._events.has_key(account): |
|---|
| 74 | self._events[account] = {jid: [event]} |
|---|
| 75 | # no such jid before ? |
|---|
| 76 | elif not self._events[account].has_key(jid): |
|---|
| 77 | self._events[account][jid] = [event] |
|---|
| 78 | else: |
|---|
| 79 | self._events[account][jid].append(event) |
|---|
| 80 | if event.show_in_systray and gajim.interface.systray_capabilities: |
|---|
| 81 | gajim.interface.systray.set_img() |
|---|
| 82 | |
|---|
| 83 | def remove_events(self, account, jid, event = None, types = []): |
|---|
| 84 | '''if event is not specified, remove all events from this jid, |
|---|
| 85 | optionnaly only from given type |
|---|
| 86 | return True if no such event found''' |
|---|
| 87 | if not self._events.has_key(account): |
|---|
| 88 | return True |
|---|
| 89 | if not self._events[account].has_key(jid): |
|---|
| 90 | return True |
|---|
| 91 | if event: # remove only one event |
|---|
| 92 | if event in self._events[account][jid]: |
|---|
| 93 | if len(self._events[account][jid]) == 1: |
|---|
| 94 | del self._events[account][jid] |
|---|
| 95 | else: |
|---|
| 96 | self._events[account][jid].remove(event) |
|---|
| 97 | if event.show_in_systray and gajim.interface.systray_capabilities: |
|---|
| 98 | gajim.interface.systray.set_img() |
|---|
| 99 | return |
|---|
| 100 | else: |
|---|
| 101 | return True |
|---|
| 102 | if types: |
|---|
| 103 | new_list = [] # list of events to keep |
|---|
| 104 | for ev in self._events[account][jid]: |
|---|
| 105 | if ev.type_ not in types: |
|---|
| 106 | new_list.append(ev) |
|---|
| 107 | if len(new_list) == len(self._events[account][jid]): |
|---|
| 108 | return True |
|---|
| 109 | if new_list: |
|---|
| 110 | self._events[account][jid] = new_list |
|---|
| 111 | else: |
|---|
| 112 | del self._events[account][jid] |
|---|
| 113 | if gajim.interface.systray_capabilities: |
|---|
| 114 | gajim.interface.systray.set_img() |
|---|
| 115 | return |
|---|
| 116 | # no event nor type given, remove them all |
|---|
| 117 | del self._events[account][jid] |
|---|
| 118 | if gajim.interface.systray_capabilities: |
|---|
| 119 | gajim.interface.systray.set_img() |
|---|
| 120 | |
|---|
| 121 | def change_jid(self, account, old_jid, new_jid): |
|---|
| 122 | if not self._events[account].has_key(old_jid): |
|---|
| 123 | return |
|---|
| 124 | if self._events[account].has_key(new_jid): |
|---|
| 125 | self._events[account][new_jid] += self._events[account][old_jid] |
|---|
| 126 | else: |
|---|
| 127 | self._events[account][new_jid] = self._events[account][old_jid] |
|---|
| 128 | del self._events[account][old_jid] |
|---|
| 129 | |
|---|
| 130 | def get_nb_events(self, types = [], account = None): |
|---|
| 131 | return self._get_nb_events(types = types, account = account) |
|---|
| 132 | |
|---|
| 133 | def get_events(self, account, jid = None, types = []): |
|---|
| 134 | '''returns all events from the given account of the form |
|---|
| 135 | {jid1: [], jid2: []} |
|---|
| 136 | if jid is given, returns all events from the given jid in a list: [] |
|---|
| 137 | optionnaly only from given type''' |
|---|
| 138 | if not self._events.has_key(account): |
|---|
| 139 | return [] |
|---|
| 140 | if not jid: |
|---|
| 141 | events_list = {} # list of events |
|---|
| 142 | for jid_ in self._events[account]: |
|---|
| 143 | events = [] |
|---|
| 144 | for ev in self._events[account][jid_]: |
|---|
| 145 | if not types or ev.type_ in types: |
|---|
| 146 | events.append(ev) |
|---|
| 147 | if events: |
|---|
| 148 | events_list[jid_] = events |
|---|
| 149 | return events_list |
|---|
| 150 | if not self._events[account].has_key(jid): |
|---|
| 151 | return [] |
|---|
| 152 | events_list = [] # list of events |
|---|
| 153 | for ev in self._events[account][jid]: |
|---|
| 154 | if not types or ev.type_ in types: |
|---|
| 155 | events_list.append(ev) |
|---|
| 156 | return events_list |
|---|
| 157 | |
|---|
| 158 | def get_first_event(self, account, jid = None, type_ = None): |
|---|
| 159 | '''Return the first event of type type_ if given''' |
|---|
| 160 | events_list = self.get_events(account, jid, type_) |
|---|
| 161 | # be sure it's bigger than latest event |
|---|
| 162 | first_event_time = time.time() + 1 |
|---|
| 163 | first_event = None |
|---|
| 164 | for event in events_list: |
|---|
| 165 | if event.time_ < first_event_time: |
|---|
| 166 | first_event_time = event.time_ |
|---|
| 167 | first_event = event |
|---|
| 168 | return first_event |
|---|
| 169 | |
|---|
| 170 | def _get_nb_events(self, account = None, jid = None, attribute = None, types = []): |
|---|
| 171 | '''return the number of pending events''' |
|---|
| 172 | nb = 0 |
|---|
| 173 | if account: |
|---|
| 174 | accounts = [account] |
|---|
| 175 | else: |
|---|
| 176 | accounts = self._events.keys() |
|---|
| 177 | for acct in accounts: |
|---|
| 178 | if not self._events.has_key(acct): |
|---|
| 179 | continue |
|---|
| 180 | if jid: |
|---|
| 181 | jids = [jid] |
|---|
| 182 | else: |
|---|
| 183 | jids = self._events[acct].keys() |
|---|
| 184 | for j in jids: |
|---|
| 185 | if not self._events[acct].has_key(j): |
|---|
| 186 | continue |
|---|
| 187 | for event in self._events[acct][j]: |
|---|
| 188 | if types and event.type_ not in types: |
|---|
| 189 | continue |
|---|
| 190 | if not attribute or \ |
|---|
| 191 | attribute == 'systray' and event.show_in_systray or \ |
|---|
| 192 | attribute == 'roster' and event.show_in_roster: |
|---|
| 193 | nb += 1 |
|---|
| 194 | return nb |
|---|
| 195 | |
|---|
| 196 | def _get_some_events(self, attribute): |
|---|
| 197 | '''attribute in systray, roster''' |
|---|
| 198 | events = {} |
|---|
| 199 | for account in self._events: |
|---|
| 200 | events[account] = {} |
|---|
| 201 | for jid in self._events[account]: |
|---|
| 202 | events[account][jid] = [] |
|---|
| 203 | for event in self._events[account][jid]: |
|---|
| 204 | if attribute == 'systray' and event.show_in_systray or \ |
|---|
| 205 | attribute == 'roster' and event.show_in_roster: |
|---|
| 206 | events[account][jid].append(event) |
|---|
| 207 | if not events[account][jid]: |
|---|
| 208 | del events[account][jid] |
|---|
| 209 | if not events[account]: |
|---|
| 210 | del events[account] |
|---|
| 211 | return events |
|---|
| 212 | |
|---|
| 213 | def _get_first_event_with_attribute(self, events): |
|---|
| 214 | '''get the first event |
|---|
| 215 | events is in the form {account1: {jid1: [ev1, ev2], },. }''' |
|---|
| 216 | # be sure it's bigger than latest event |
|---|
| 217 | first_event_time = time.time() + 1 |
|---|
| 218 | first_account = None |
|---|
| 219 | first_jid = None |
|---|
| 220 | first_event = None |
|---|
| 221 | for account in events: |
|---|
| 222 | for jid in events[account]: |
|---|
| 223 | for event in events[account][jid]: |
|---|
| 224 | if event.time_ < first_event_time: |
|---|
| 225 | first_event_time = event.time_ |
|---|
| 226 | first_account = account |
|---|
| 227 | first_jid = jid |
|---|
| 228 | first_event = event |
|---|
| 229 | return first_account, first_jid, first_event |
|---|
| 230 | |
|---|
| 231 | def get_nb_systray_events(self, types = []): |
|---|
| 232 | '''returns the number of events displayed in roster''' |
|---|
| 233 | return self._get_nb_events(attribute = 'systray', types = types) |
|---|
| 234 | |
|---|
| 235 | def get_systray_events(self): |
|---|
| 236 | '''return all events that must be displayed in systray: |
|---|
| 237 | {account1: {jid1: [ev1, ev2], },. }''' |
|---|
| 238 | return self._get_some_events('systray') |
|---|
| 239 | |
|---|
| 240 | def get_first_systray_event(self): |
|---|
| 241 | events = self.get_systray_events() |
|---|
| 242 | return self._get_first_event_with_attribute(events) |
|---|
| 243 | |
|---|
| 244 | def get_nb_roster_events(self, account = None, jid = None, types = []): |
|---|
| 245 | '''returns the number of events displayed in roster''' |
|---|
| 246 | return self._get_nb_events(attribute = 'roster', account = account, |
|---|
| 247 | jid = jid, types = types) |
|---|
| 248 | |
|---|
| 249 | def get_roster_events(self): |
|---|
| 250 | '''return all events that must be displayed in roster: |
|---|
| 251 | {account1: {jid1: [ev1, ev2], },. }''' |
|---|
| 252 | return self._get_some_events('roster') |
|---|