X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Fdialcentral%2Fgc_dialer.py;h=fc8c85a2ddc6494b3fac6f7737e96a1331f64037;hb=17decda1876ac262c523430896c9e1c15637c264;hp=a47a467ccee506b79101a9208f299bafdd9d0f21;hpb=18a135990fa0ed808c784b1ba4f8f5025239a981;p=gc-dialer diff --git a/src/dialcentral/gc_dialer.py b/src/dialcentral/gc_dialer.py index a47a467..fc8c85a 100755 --- a/src/dialcentral/gc_dialer.py +++ b/src/dialcentral/gc_dialer.py @@ -1,6 +1,6 @@ #!/usr/bin/python2.5 -# GC Dialer - Front end for Google's Grand Central service. +# DialCentral - Front end for Google's Grand Central service. # Copyright (C) 2008 Mark Bergman bergman AT merctech DOT com # # This library is free software; you can redistribute it and/or @@ -19,7 +19,7 @@ """ -Grandcentral Dialer +DialCentral: A phone dialer using GrandCentral """ import sys @@ -38,13 +38,6 @@ try: except ImportError: hildon = None -import socket - - -gtk.gdk.threads_init() -#This changes the default, system wide, socket timeout so that a hung server will not completly -#hork the application -socket.setdefaulttimeout(5) def make_ugly(prettynumber): @@ -123,7 +116,7 @@ def make_idler(func): except StopIteration: del a[:] return False - + decorated_func.__name__ = func.__name__ decorated_func.__doc__ = func.__doc__ decorated_func.__dict__.update(func.__dict__) @@ -141,12 +134,12 @@ class DummyAddressBook(object): @returns Iterable of (Address Book Factory, Book Id, Book Name) """ yield self, "", "None" - + def open_addressbook(self, bookId): return self @staticmethod - def factory_short_name(): + def contact_source_short_name(contactId): return "" @staticmethod @@ -168,6 +161,65 @@ class DummyAddressBook(object): 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 + + def get_contact_details(self, 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): @@ -216,7 +268,7 @@ class PhoneTypeSelector(object): self._typeviewselection.unselect_all() self._dialog.hide() return phoneNumber - + def _on_phonetype_select(self, *args): self._dialog.response(gtk.RESPONSE_OK) @@ -232,9 +284,9 @@ class Dialpad(object): __app_magic__ = 0xdeadbeef _glade_files = [ - './gc_dialer.glade', - '../lib/gc_dialer.glade', '/usr/lib/dialcentral/gc_dialer.glade', + os.path.join(os.path.dirname(__file__), "gc_dialer.glade"), + os.path.join(os.path.dirname(__file__), "../lib/gc_dialer.glade"), ] def __init__(self): @@ -256,7 +308,7 @@ class Dialpad(object): self._contactsviewselection = None self._clearall_id = None - + for path in Dialpad._glade_files: if os.path.isfile(path): self._widgetTree = gtk.glade.XML(path) @@ -287,6 +339,8 @@ class Dialpad(object): self._widgetTree.get_widget("callbackcombo").get_child().set_property('hildon-input-mode', (1 << 4)) self._widgetTree.get_widget("usernameentry").set_property('hildon-input-mode', 7) self._widgetTree.get_widget("passwordentry").set_property('hildon-input-mode', 7|(1 << 29)) + hildon.hildon_helper_set_thumb_scrollbar(self._widgetTree.get_widget('contacts_scrolledwindow'), True) + hildon.hildon_helper_set_thumb_scrollbar(self._widgetTree.get_widget('recent_scrolledwindow'), True) gtkMenu = self._widgetTree.get_widget("dialpad_menubar") menu = gtk.Menu() @@ -345,11 +399,13 @@ class Dialpad(object): """ 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 - self._gcBackend = GCDialer() + import gc_backend + import evo_backend + import gmail_backend + import maemo_backend + + self._gcBackend = gc_backend.GCDialer() try: import osso @@ -379,21 +435,24 @@ class Dialpad(object): warnings.warn("No Internet Connectivity API ", UserWarning, 2) - self._addressBookFactories = [ + addressBooks = [ self._gcBackend, + evo_backend.EvolutionAddressBook(), 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]) - + gtk.gdk.threads_enter() self._booksList = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING) gtk.gdk.threads_leave() for (factoryId, bookId), (factoryName, bookName) in self.get_addressbooks(): if factoryName and bookName: - entryName = "%s: %s" % (factoryName, bookName) + entryName = "%s: %s" % (factoryName, bookName) elif factoryName: entryName = factoryName elif bookName: @@ -455,6 +514,13 @@ class Dialpad(object): # 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) @@ -499,6 +565,7 @@ class Dialpad(object): combobox.get_child().set_text(make_pretty(self._gcBackend.get_callback_number())) def _idly_populate_recentview(self): + self._recenttime = time.time() self._recentmodel.clear() for personsName, phoneNumber, date, action in self._gcBackend.get_recent(): @@ -508,11 +575,11 @@ class Dialpad(object): self._recentmodel.append(item) gtk.gdk.threads_leave() - self._recenttime = time.time() return False - @make_idler def _idly_populate_contactsview(self): + #@todo Add a lock so only one code path can be in here at a time + self._contactstime = time.time() self._contactsmodel.clear() # completely disable updating the treeview while we populate the data @@ -520,16 +587,15 @@ class Dialpad(object): contactsview.freeze_child_notify() contactsview.set_model(None) - contactType = (self._addressBook.factory_short_name(),) - for contactId, contactName in self._addressBook.get_contacts(): + addressBook = self._addressBook + for contactId, contactName in addressBook.get_contacts(): + contactType = (addressBook.contact_source_short_name(contactId),) self._contactsmodel.append(contactType + (contactName, "", contactId) + ("",)) - yield # restart the treeview data rendering contactsview.set_model(self._contactsmodel) contactsview.thaw_child_notify() - - self._contactstime = time.time() + return False def attempt_login(self, numOfAttempts = 1): """ @@ -543,7 +609,7 @@ class Dialpad(object): if self._gcBackend.is_authed(): return True - + for x in xrange(numOfAttempts): gtk.gdk.threads_enter() @@ -567,6 +633,8 @@ class Dialpad(object): 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) @@ -583,11 +651,11 @@ class Dialpad(object): for i, factory in enumerate(self._addressBookFactories): for bookFactory, bookId, bookName in factory.get_addressbooks(): yield (i, bookId), (factory.factory_name(), bookName) - + def open_addressbook(self, bookFactoryId, bookId): self._addressBook = self._addressBookFactories[bookFactoryId].open_addressbook(bookId) self._contactstime = 0 - gobject.idle_add(self._idly_populate_contactsview) + threading.Thread(target=self._idly_populate_contactsview).start() def set_number(self, number): """ @@ -645,7 +713,7 @@ class Dialpad(object): self._isFullScreen = True else: self._isFullScreen = False - + def _on_key_press(self, widget, event, *args): """ @note Hildon specific @@ -727,12 +795,15 @@ class Dialpad(object): self._contactsviewselection.unselect_all() def _on_notebook_switch_page(self, notebook, page, page_num): - if page_num == 1 and 300 < (time.time() - self._contactstime): - threading.Thread(target=self._idly_populate_contactsview).start() - elif page_num == 2 and 300 < (time.time() - self._recenttime): - threading.Thread(target=self._idly_populate_recentview).start() - #elif page_num == 3 and self._callbackNeedsSetup: - # gobject.idle_add(self._idly_populate_callback_combo) + if page_num == 1: + if 300 < (time.time() - self._contactstime): + threading.Thread(target=self._idly_populate_contactsview).start() + elif page_num == 3: + if 300 < (time.time() - self._recenttime): + threading.Thread(target=self._idly_populate_recentview).start() + #elif page_num == 2: + # self._callbackNeedsSetup:: + # gobject.idle_add(self._idly_populate_callback_combo) tabTitle = self._notebook.get_tab_label(self._notebook.get_nth_page(page_num)).get_text() if hildon is not None: @@ -777,7 +848,7 @@ class Dialpad(object): self.set_number("") def _on_digit_clicked(self, widget): - self.set_number(self._phonenumber + widget.get_name()[5]) + self.set_number(self._phonenumber + widget.get_name()[-1]) def _on_backspace(self, widget): self.set_number(self._phonenumber[:-1]) @@ -804,7 +875,7 @@ class Dialpad(object): dlg.set_authors(["", "Eric Warnke ", "Ed Page "]) dlg.run() dlg.destroy() - + def run_doctest(): import doctest