Merging in the tweaks branch
authorepage <eopage@byu.net>
Fri, 3 Oct 2008 00:05:36 +0000 (00:05 +0000)
committerepage <eopage@byu.net>
Fri, 3 Oct 2008 00:05:36 +0000 (00:05 +0000)
git-svn-id: file:///svnroot/gc-dialer/trunk@160 c39d3808-3fe2-4d86-a59f-b7f623ee9f21

src/dialcentral/evo_backend.py
src/dialcentral/gc_backend.py
src/dialcentral/gc_dialer.py
src/dialcentral/gmail_backend.py [new file with mode: 0644]
src/dialcentral/maemo_backend.py [new file with mode: 0644]

index c094c2e..c1c0487 100644 (file)
@@ -39,7 +39,17 @@ class EvolutionAddressBook(object):
                        return
 
                self._phoneTypes = None
                        return
 
                self._phoneTypes = None
-               self._bookId = bookId if bookId is not None else self.get_addressbooks().next()[1]
+               if bookId is not None:
+                       self._bookId = bookId
+               else:
+                       try:
+                               self._bookId = [
+                                       bookData[1]
+                                               for bookData in self.get_addressbooks()
+                               ][0]
+                       except IndexError:
+                               global evolution
+                               evolution = None
                self._book = evolution.ebook.open_addressbook(self._bookId)
        
        @classmethod
                self._book = evolution.ebook.open_addressbook(self._bookId)
        
        @classmethod
@@ -66,7 +76,7 @@ class EvolutionAddressBook(object):
                return self
 
        @staticmethod
                return self
 
        @staticmethod
-       def factory_short_name():
+       def contact_source_short_name(contactId):
                return "Evo"
 
        @staticmethod
                return "Evo"
 
        @staticmethod
@@ -81,13 +91,13 @@ class EvolutionAddressBook(object):
                        return
 
                for contact in self._book.get_all_contacts():
                        return
 
                for contact in self._book.get_all_contacts():
-                       yield contact.get_uid(), contact.props.full_name
+                       yield str(contact.get_uid()), contact.props.full_name
        
        def get_contact_details(self, contactId):
                """
                @returns Iterable of (Phone Type, Phone Number)
                """
        
        def get_contact_details(self, contactId):
                """
                @returns Iterable of (Phone Type, Phone Number)
                """
-               contact = self._book.get_contact(contactId)
+               contact = self._book.get_contact(int(contactId))
 
                if self._phoneTypes is None and contact is not None:
                        self._phoneTypes = [pt for pt in dir(contact.props) if "phone" in pt.lower()]
 
                if self._phoneTypes is None and contact is not None:
                        self._phoneTypes = [pt for pt in dir(contact.props) if "phone" in pt.lower()]
@@ -97,7 +107,8 @@ class EvolutionAddressBook(object):
                        if isinstance(phoneNumber, str):
                                yield phoneType, phoneNumber
 
                        if isinstance(phoneNumber, str):
                                yield phoneType, phoneNumber
 
-def print_addressbooks():
+
+def print_evobooks():
        """
        Included here for debugging.
 
        """
        Included here for debugging.
 
index d1641de..cda6eb6 100644 (file)
@@ -31,6 +31,11 @@ import warnings
 
 from browser_emu import MozillaEmulator
 
 
 from browser_emu import MozillaEmulator
 
+import socket
+
+
+socket.setdefaulttimeout(5)
+
 
 class GCDialer(object):
        """
 
 class GCDialer(object):
        """
@@ -268,7 +273,7 @@ class GCDialer(object):
                return self
 
        @staticmethod
                return self
 
        @staticmethod
-       def factory_short_name():
+       def contact_source_short_name(contactId):
                return "GC"
 
        @staticmethod
                return "GC"
 
        @staticmethod
index a47a467..effb344 100755 (executable)
@@ -146,7 +146,7 @@ class DummyAddressBook(object):
                return self
 
        @staticmethod
                return self
 
        @staticmethod
-       def factory_short_name():
+       def contact_source_short_name(contactId):
                return ""
 
        @staticmethod
                return ""
 
        @staticmethod
@@ -168,6 +168,66 @@ class DummyAddressBook(object):
                return []
 
 
                return []
 
 
+class MergedAddressBook(object):
+       """
+       Merger of all addressbooks
+       """
+
+       def __init__(self, addressbooks, sorter = None):
+               self.__addressbooks = addressbooks
+               self.__sort_contacts = sorter if sorter is not None else self.null_sorter
+
+       def get_addressbooks(self):
+               """
+               @returns Iterable of (Address Book Factory, Book Id, Book Name)
+               """
+               yield self, "", ""
+       
+       def open_addressbook(self, bookId):
+               return self
+
+       def contact_source_short_name(self, contactId):
+               bookIndex, originalId = contactId.split("-", 1)
+               return self.__addressbooks[int(bookIndex)].contact_source_short_name(originalId)
+
+       @staticmethod
+       def factory_name():
+               return "All Contacts"
+
+       def get_contacts(self):
+               """
+               @returns Iterable of (contact id, contact name)
+               """
+               contacts = (
+                       ("-".join([str(bookIndex), contactId]), contactName)
+                               for (bookIndex, addressbook) in enumerate(self.__addressbooks)
+                                       for (contactId, contactName) in addressbook.get_contacts()
+               )
+               sortedContacts = self.__sort_contacts(contacts)
+               return sortedContacts
+
+       @staticmethod
+       def get_contact_details(contactId):
+               """
+               @returns Iterable of (Phone Type, Phone Number)
+               """
+               bookIndex, originalId = contactId.split("-", 1)
+               return self.__addressbooks[int(bookIndex)].get_contact_details(originalId)
+
+       @staticmethod
+       def null_sorter(contacts):
+               return contacts
+
+       @staticmethod
+       def basic_lastname_sorter(contacts):
+               contactsWithKey = [
+                       (contactName.rsplit(" ", 1)[-1], (contactId, contactName))
+                               for (contactId, contactName) in contacts
+               ]
+               contactsWithKey.sort()
+               return (contactData for (lastName, contactData) in contactsWithKey)
+
+
 class PhoneTypeSelector(object):
 
        def __init__(self, widgetTree, gcBackend):
 class PhoneTypeSelector(object):
 
        def __init__(self, widgetTree, gcBackend):
@@ -346,10 +406,12 @@ class Dialpad(object):
                If something can be done after the UI loads, push it here so it's not blocking the UI
                """
                
                If something can be done after the UI loads, push it here so it's not blocking the UI
                """
                
-               from gc_backend import GCDialer
-               from evo_backend import EvolutionAddressBook
+               import gc_backend
+               import evo_backend
+               import gmail_backend
+               import maemo_backend
 
 
-               self._gcBackend = GCDialer()
+               self._gcBackend = gc_backend.GCDialer()
 
                try:
                        import osso
 
                try:
                        import osso
@@ -379,11 +441,14 @@ class Dialpad(object):
                        warnings.warn("No Internet Connectivity API ", UserWarning, 2)
 
 
                        warnings.warn("No Internet Connectivity API ", UserWarning, 2)
 
 
-               self._addressBookFactories = [
+               addressBooks = [
                        self._gcBackend,
                        self._gcBackend,
+                       evo_backend.EvolutionAddressBook(),
                        DummyAddressBook(),
                        DummyAddressBook(),
-                       EvolutionAddressBook(),
                ]
                ]
+               mergedBook = MergedAddressBook(addressBooks, MergedAddressBook.basic_lastname_sorter)
+               self._addressBookFactories = list(addressBooks)
+               self._addressBookFactories.insert(0, mergedBook)
                self._addressBook = None
                self.open_addressbook(*self.get_addressbooks().next()[0][0:2])
        
                self._addressBook = None
                self.open_addressbook(*self.get_addressbooks().next()[0][0:2])
        
@@ -455,6 +520,13 @@ class Dialpad(object):
                # Add the column to the treeview
                column = gtk.TreeViewColumn("Contact")
 
                # Add the column to the treeview
                column = gtk.TreeViewColumn("Contact")
 
+               #displayContactSource = False
+               displayContactSource = True
+               if displayContactSource:
+                       textrenderer = gtk.CellRendererText()
+                       column.pack_start(textrenderer, expand=False)
+                       column.add_attribute(textrenderer, 'text', 0)
+
                textrenderer = gtk.CellRendererText()
                column.pack_start(textrenderer, expand=True)
                column.add_attribute(textrenderer, 'text', 1)
                textrenderer = gtk.CellRendererText()
                column.pack_start(textrenderer, expand=True)
                column.add_attribute(textrenderer, 'text', 1)
@@ -520,8 +592,8 @@ class Dialpad(object):
                contactsview.freeze_child_notify()
                contactsview.set_model(None)
 
                contactsview.freeze_child_notify()
                contactsview.set_model(None)
 
-               contactType = (self._addressBook.factory_short_name(),)
                for contactId, contactName in self._addressBook.get_contacts():
                for contactId, contactName in self._addressBook.get_contacts():
+                       contactType = (self._addressBook.contact_source_short_name(contactId),)
                        self._contactsmodel.append(contactType + (contactName, "", contactId) + ("",))
                        yield
 
                        self._contactsmodel.append(contactType + (contactName, "", contactId) + ("",))
                        yield
 
@@ -567,6 +639,8 @@ class Dialpad(object):
                                gtk.gdk.threads_leave()
                                return True
 
                                gtk.gdk.threads_leave()
                                return True
 
+               return False
+
        def display_error_message(self, msg):
                error_dialog = gtk.MessageDialog(None, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, msg)
 
        def display_error_message(self, msg):
                error_dialog = gtk.MessageDialog(None, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, msg)
 
diff --git a/src/dialcentral/gmail_backend.py b/src/dialcentral/gmail_backend.py
new file mode 100644 (file)
index 0000000..f29c7ca
--- /dev/null
@@ -0,0 +1,104 @@
+#!/usr/bin/python
+
+# GC Dialer - Front end for Google's Grand Central service.
+# Copyright (C) 2008  Eric Warnke ericew AT gmail DOT com
+# 
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+# 
+# This library 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
+# Lesser General Public License for more details.
+# 
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+"""
+GMail Contacts Support
+"""
+
+
+import warnings
+
+
+try:
+       import libgmail
+except ImportError:
+       libgmail = None
+
+
+class GMailAddressBook(object):
+       """
+       @note Combined the factory and the addressbook for "simplicity" and "cutting down" the number of allocations/deallocations
+       """
+
+       def __init__(self, username, password):
+               if not self.is_supported():
+                       return
+
+               self._account = libgmail.GmailAccount(username, password)
+               self._gmailContacts = self._account.getContacts()
+       
+       @classmethod
+       def is_supported(cls):
+               return libgmail is not None
+
+       def get_addressbooks(self):
+               """
+               @returns Iterable of (Address Book Factory, Book Id, Book Name)
+               """
+               if not self.is_supported():
+                       return
+
+               yield self, "", ""
+       
+       def open_addressbook(self, bookId):
+               return self
+
+       @staticmethod
+       def contact_source_short_name(contactId):
+               return "G"
+
+       @staticmethod
+       def factory_name():
+               return "GMail"
+
+       def get_contacts(self):
+               """
+               @returns Iterable of (contact id, contact name)
+               """
+               if not self.is_supported():
+                       return
+               pass
+       
+       def get_contact_details(self, contactId):
+               """
+               @returns Iterable of (Phone Type, Phone Number)
+               """
+               pass
+
+
+def print_gbooks(username, password):
+       """
+       Included here for debugging.
+
+       Either insert it into the code or launch python with the "-i" flag
+       """
+       if not GMailAddressBook.is_supported():
+               print "No GMail Support"
+               return
+
+       gab = GMailAddressBook(username, password)
+       for book in gab.get_addressbooks():
+               gab = gab.open_addressbook(book[1])
+               print book
+               for contact in gab.get_contacts():
+                       print "\t", contact
+                       for details in gab.get_contact_details(contact[0]):
+                               print "\t\t", details
+       print gab._gmailContacts
diff --git a/src/dialcentral/maemo_backend.py b/src/dialcentral/maemo_backend.py
new file mode 100644 (file)
index 0000000..24a27d9
--- /dev/null
@@ -0,0 +1,109 @@
+#!/usr/bin/python
+
+# GC Dialer - Front end for Google's Grand Central service.
+# Copyright (C) 2008  Eric Warnke ericew AT gmail DOT com
+# 
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+# 
+# This library 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
+# Lesser General Public License for more details.
+# 
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+"""
+Maemo Contacts Support
+"""
+
+
+import warnings
+
+try:
+       import abook
+except ImportError:
+       abook = None
+
+try:
+       import evolution.ebook as ebook
+except ImportError:
+       ebook = None
+
+
+class MaemoAddressBook(object):
+       """
+       @note Combined the factory and the addressbook for "simplicity" and "cutting down" the number of allocations/deallocations
+       """
+
+       def __init__(self, contextName, context):
+               if not self.is_supported():
+                       return
+               
+               abook.init_with_name(contextName, context)
+               self._book = abook.all_group_get()
+       
+       @classmethod
+       def is_supported(cls):
+               return abook is not None and ebook is not None
+
+       def get_addressbooks(self):
+               """
+               @returns Iterable of (Address Book Factory, Book Id, Book Name)
+               """
+               if not self.is_supported():
+                       return
+
+               yield self, "", ""
+       
+       def open_addressbook(self, bookId):
+               return self
+
+       @staticmethod
+       def contact_source_short_name(contactId):
+               return "M"
+
+       @staticmethod
+       def factory_name():
+               return "Maemo"
+
+       def get_contacts(self):
+               """
+               @returns Iterable of (contact id, contact name)
+               """
+               if not self.is_supported():
+                       return
+               pass
+       
+       def get_contact_details(self, contactId):
+               """
+               @returns Iterable of (Phone Type, Phone Number)
+               """
+               pass
+
+
+def print_maemobooks():
+       """
+       Included here for debugging.
+
+       Either insert it into the code or launch python with the "-i" flag
+       """
+       if not MaemoAddressBook.is_supported():
+               print "No GMail Support"
+               return
+
+       mab = MaemoAddressBook()
+       for book in mab.get_addressbooks():
+               mab = mab.open_addressbook(book[1])
+               print book
+               for contact in mab.get_contacts():
+                       print "\t", contact
+                       for details in mab.get_contact_details(contact[0]):
+                               print "\t\t", details
+       print mab._gmailContacts
+