Lots more bug fixes
[theonering] / src / gvoice / addressbook.py
1 #!/usr/bin/python
2
3
4 import logging
5
6 import util.coroutines as coroutines
7
8
9 _moduleLogger = logging.getLogger("gvoice.addressbook")
10
11
12 class Addressbook(object):
13
14         def __init__(self, backend):
15                 self._backend = backend
16                 self._contacts = {}
17                 self._addedContacts = set()
18                 self._removedContacts = set()
19                 self._changedContacts = set()
20
21                 self.updateSignalHandler = coroutines.CoTee()
22
23         def update(self, force=False):
24                 if not force and self._contacts:
25                         return
26                 oldContacts = self._contacts
27                 oldContactIds = set(self.get_contacts())
28
29                 self._contacts = {}
30                 self._populate_contacts()
31                 newContactIds = set(self.get_contacts())
32
33                 self._addedContacts = newContactIds - oldContactIds
34                 self._removedContacts = oldContactIds - newContactIds
35                 self._changedContacts = set(
36                         contactId
37                         for contactId in newContactIds.intersection(oldContactIds)
38                         if self._has_contact_changed(contactId, oldContacts)
39                 )
40
41                 if self._addedContacts or self._removedContacts or self._changedContacts:
42                         message = self, self._addedContacts, self._removedContacts, self._changedContacts
43                         self.updateSignalHandler.stage.send(message)
44
45         def get_contacts(self):
46                 return self._contacts.iterkeys()
47
48         def get_contact_name(self, contactId):
49                 return self._contacts[contactId][0]
50
51         def get_contact_details(self, contactId):
52                 self._populate_contact_details(contactId)
53                 return self._get_contact_details(contactId)
54
55         def _populate_contacts(self):
56                 if self._contacts:
57                         return
58                 contacts = self._backend.get_contacts()
59                 for contactId, contactDetails in contacts:
60                         contactName = contactDetails["name"]
61                         contactNumbers = [
62                                 (numberDetails.get("phoneType", "Mobile"), numberDetails["phoneNumber"])
63                                 for numberDetails in contactDetails["numbers"]
64                         ]
65                         self._contacts[contactId] = (contactName, contactNumbers)
66
67         def _populate_contact_details(self, contactId):
68                 if self._get_contact_details(contactId):
69                         return
70                 self._get_contact_details(contactId).extend(
71                         self._backend.get_contact_details(contactId)
72                 )
73
74         def _get_contact_details(self, contactId):
75                 return self._contacts[contactId][1]
76
77         def _has_contact_changed(self, contactId, oldContacts):
78                 oldContact = oldContacts[contactId]
79                 oldContactName = oldContact[0]
80                 oldContactDetails = oldContact[1]
81                 if oldContactName != self.get_contact_name(contactId):
82                         return True
83                 if not oldContactDetails:
84                         return False
85                 # if its already in the old cache, purposefully add it into the new cache
86                 return oldContactDetails != self.get_contact_details(contactId)