-#!/usr/bin/python2.5
+#!/usr/bin/python
+
+# GC Dialer - 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
+# 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
"""
Grandcentral Dialer
-Python front-end to a wget script to use grandcentral.com to place outbound VOIP calls.
-(C) 2008 Mark Bergman
-bergman@merctech.com
"""
try:
import osso
- try:
- import abook
- import evolution.ebook as evobook
- except ImportError:
- abook = None
- evobook = None
except ImportError:
osso = None
doctest = None
optparse = None
-from gcbackend import GCDialer
+from gc_backend import GCDialer
+from evo_backend import EvolutionAddressBook
import socket
"""
a = []
- def callable(*args, **kwds):
+ def decorated_func(*args, **kwds):
if not a:
a.append(func(*args, **kwds))
try:
a[0].next()
return True
except StopIteration:
+ del a[:]
return False
- callable.__name__ = func.__name__
- callable.__doc__ = func.__doc__
- callable.__dict__.update(func.__dict__)
+ decorated_func.__name__ = func.__name__
+ decorated_func.__doc__ = func.__doc__
+ decorated_func.__dict__.update(func.__dict__)
- return callable
+ return decorated_func
+
+
+class DummyAddressBook(object):
+ """
+ Minimal example of both an addressbook factory and an addressbook
+ """
+
+ def get_addressbooks(self):
+ """
+ @returns Iterable of (Address Book Factory, Book Id, Book Name)
+ """
+ yield self, "", "None"
+
+ def open_addressbook(self, bookId):
+ return self
+
+ @staticmethod
+ def factory_name():
+ return ""
+
+ def get_contacts(self):
+ """
+ @returns Iterable of (contact id, contact name)
+ """
+ return []
+
+ def get_contact_details(self, contactId):
+ """
+ @returns Iterable of (Phone Type, Phone Number)
+ """
+ return []
+
+
+class SettingsDialog(object):
+ """
+ @todo Remove this. Currently its only used for addressbooks and I want to make that a combo box on the contacts tab
+ """
+
+ def __init__(self, widgetTree, gcDialer):
+ self._gcDialer = gcDialer
+ self._widgetTree = widgetTree
+ self._dialog = self._widgetTree.get_widget("settings_dialog")
+
+ self._applyButton = self._widgetTree.get_widget("apply_settings")
+ self._applyButton.connect("clicked", self.custom_button_response(gtk.RESPONSE_OK))
+
+ self._cancelButton = self._widgetTree.get_widget("cancel_settings")
+ self._cancelButton.connect("clicked", self.custom_button_response(gtk.RESPONSE_CANCEL))
+
+ self._booksList = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
+ for (factoryId, bookId), (factoryName, bookName) in self._gcDialer.get_addressbooks():
+ row = (str(factoryId), bookId, factoryName, bookName)
+ self._booksList.append(row)
+
+ self._booksView = self._widgetTree.get_widget("books_view")
+ self._booksView.set_model(self._booksList)
+
+ # Add the column to the treeview
+ column = gtk.TreeViewColumn("Addressbook")
+
+ textrenderer = gtk.CellRendererText()
+ column.pack_start(textrenderer, expand=False)
+ column.add_attribute(textrenderer, 'text', 2)
+
+ textrenderer = gtk.CellRendererText()
+ column.pack_start(textrenderer, expand=True)
+ column.add_attribute(textrenderer, 'text', 3)
+
+ column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
+ column.set_sort_column_id(2)
+ column.set_visible(True)
+ self._booksView.append_column(column)
+
+ self._booksViewSelection = self._booksView.get_selection()
+ self._booksViewSelection.set_mode(gtk.SELECTION_SINGLE)
+ self.reset()
+
+ def reset(self):
+ pass
+
+ def custom_button_response(self, response):
+
+ def button_handler(*args, **kwds):
+ self._dialog.response(response)
+
+ return button_handler
+
+ def run(self):
+ userResponse = self._dialog.run()
+
+ if userResponse == gtk.RESPONSE_OK:
+ model, itr = self._booksViewSelection.get_selected()
+ if itr:
+ factoryId = int(self._booksList.get_value(itr, 0))
+ bookId = self._booksList.get_value(itr, 1)
+ self._gcDialer.open_addressbook(factoryId, bookId)
+ self._booksViewSelection.unselect_all()
+ else:
+ self.reset()
+
+ self._dialog.hide()
class PhoneTypeSelector(object):
class Dialpad(object):
+ __pretty_app_name__ = "Dialer"
__app_name__ = "gc_dialer"
- __version__ = "0.7.0"
+ __version__ = "0.8.0"
__app_magic__ = 0xdeadbeef
_glade_files = [
self._clipboard = gtk.clipboard_get()
self._deviceIsOnline = True
+ self.callbacklist = None
self._callbackNeedsSetup = True
self._recenttime = 0.0
self._recentmodel = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
self._recentviewselection = None
+ self._gcContactText = "GC"
+ try:
+ self._gcContactIcon = gtk.gdk.pixbuf_new_from_file_at_size('gc_contact.png', 16, 16)
+ except gobject.GError:
+ self._gcContactIcon = None
self._contactstime = 0.0
- self._contactsmodel = gtk.ListStore(
- gtk.gdk.Pixbuf,
- gobject.TYPE_STRING,
- gobject.TYPE_STRING,
- gobject.TYPE_STRING,
- gobject.TYPE_STRING
- )
+ if self._gcContactIcon is not None:
+ self._contactsmodel = gtk.ListStore(
+ gtk.gdk.Pixbuf,
+ gobject.TYPE_STRING,
+ gobject.TYPE_STRING,
+ gobject.TYPE_STRING,
+ gobject.TYPE_STRING
+ )
+ else:
+ self._contactsmodel = gtk.ListStore(
+ gobject.TYPE_STRING,
+ gobject.TYPE_STRING,
+ gobject.TYPE_STRING,
+ gobject.TYPE_STRING,
+ gobject.TYPE_STRING
+ )
self._contactsviewselection = None
for path in Dialpad._glade_files:
global hildon
self._app = None
self._isFullScreen = False
- if hildon is not None and isinstance(self._window, gtk.Window):
+ if hildon is not None and self._window is gtk.Window:
warnings.warn("Hildon installed but glade file not updated to work with hildon", UserWarning, 2)
hildon = None
elif hildon is not None:
self._app = hildon.Program()
- self._window.set_title("Keypad")
self._app.add_window(self._window)
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)
else:
warnings.warn("No Hildon", UserWarning, 2)
+ if hildon is not None:
+ self._window.set_title("Keypad")
+ else:
+ self._window.set_title("%s - Keypad" % self.__pretty_app_name__)
+
self._osso = None
self._ebook = None
if osso is not None:
self._osso = osso.Context(Dialpad.__app_name__, Dialpad.__version__, False)
device = osso.DeviceState(self._osso)
device.set_device_state_callback(self._on_device_state_change, 0)
- if abook is not None and evobook is not None:
- abook.init_with_name(Dialpad.__app_name__, self._osso)
- self._ebook = evobook.open_addressbook("default")
- else:
- warnings.warn("No abook and No evolution address book support", UserWarning, 2)
else:
warnings.warn("No OSSO", UserWarning, 2)
"on_dialpad_quit": self._on_close,
"on_paste": self._on_paste,
"on_clear_number": self._on_clear_number,
+ "on_settings": self._on_settings,
"on_clearcookies_clicked": self._on_clearcookies_clicked,
"on_notebook_switch_page": self._on_notebook_switch_page,
self._gcBackend = GCDialer()
+ self._addressBookFactories = [
+ DummyAddressBook(),
+ EvolutionAddressBook(),
+ self._gcBackend,
+ ]
+ self._addressBook = None
+ self.open_addressbook(*self.get_addressbooks().next()[0][0:2])
+
self._phoneTypeSelector = PhoneTypeSelector(self._widgetTree, self._gcBackend)
+ self._settingsDialog = SettingsDialog(self._widgetTree, self)
if not self._gcBackend.is_authed():
self.attempt_login(2)
gobject.idle_add(self._idly_init_contacts_view)
def _idly_init_recent_view(self):
- """ Deferred initalization of the recent view treeview """
+ """
+ Deferred initalization of the recent view treeview
+ """
recentview = self._widgetTree.get_widget("recentview")
recentview.set_model(self._recentmodel)
# Add the column to the treeview
column = gtk.TreeViewColumn("Contact")
- iconrenderer = gtk.CellRendererPixbuf()
- column.pack_start(iconrenderer, expand=False)
- column.add_attribute(iconrenderer, 'pixbuf', 0)
+ if self._gcContactIcon is not None:
+ iconrenderer = gtk.CellRendererPixbuf()
+ column.pack_start(iconrenderer, expand=False)
+ column.add_attribute(iconrenderer, 'pixbuf', 0)
+ else:
+ warnings.warn("Contact icon unavailable", UserWarning, 1)
+ textrenderer = gtk.CellRendererText()
+ column.pack_start(textrenderer, expand=False)
+ column.add_attribute(textrenderer, 'text', 0)
textrenderer = gtk.CellRendererText()
column.pack_start(textrenderer, expand=True)
contactsview.set_model(None)
# get gc icon
- gc_icon = gtk.gdk.pixbuf_new_from_file_at_size('gc_contact.png', 16, 16)
- for contactId, contactName in self._gcBackend.get_contacts():
- self._contactsmodel.append((gc_icon,) + (contactName, "", contactId) + ("",))
+ if self._gcContactIcon is not None:
+ contactType = (self._gcContactIcon,)
+ else:
+ contactType = (self._gcContactText,)
+ for contactId, contactName in self._addressBook.get_contacts():
+ self._contactsmodel.append(contactType + (contactName, "", contactId) + ("",))
yield
# restart the treeview data rendering
error_dialog.connect("response", close, self)
error_dialog.run()
+ def get_addressbooks(self):
+ """
+ @returns Iterable of ((Factory Id, Book Id), (Factory Name, Book Name))
+ """
+ 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)
+
def set_number(self, number):
"""
Set the callback phonenumber
"""
self._phonenumber = make_ugly(number)
self._prettynumber = make_pretty(self._phonenumber)
- self._numberdisplay.set_label("<span size='30000' weight='bold'>%s</span>" % ( self._prettynumber ) )
+ self._numberdisplay.set_label("<span size='30000' weight='bold'>%s</span>" % (self._prettynumber))
def set_account_number(self):
"""
self._isFullScreen = True
else:
self._isFullScreen = False
+
+ def _on_settings(self, *args, **kwds):
+ self._settingsDialog.run()
def _on_key_press(self, widget, event, *args):
"""
return
contactId = self._contactsmodel.get_value(itr, 3)
- contactDetails = self._gcBackend.get_contact_details(contactId)
+ contactDetails = self._addressBook.get_contact_details(contactId)
contactDetails = [phoneNumber for phoneNumber in contactDetails]
if len(contactDetails) == 0:
elif page_num == 3 and self._callbackNeedsSetup:
gobject.idle_add(self._idly_setup_callback_combo)
- if hildon:
- hildonTitle = self._notebook.get_tab_label(self._notebook.get_nth_page(page_num)).get_text()
- self._window.set_title(hildonTitle)
+ tabTitle = self._notebook.get_tab_label(self._notebook.get_nth_page(page_num)).get_text()
+ if hildon is not None:
+ self._window.set_title(tabTitle)
+ else:
+ self._window.set_title("%s - %s" % (self.__pretty_app_name__, tabTitle))
def _on_dial_clicked(self, widget):
"""
if __name__ == "__main__":
if hildon is not None:
- gtk.set_application_name("Dialer")
+ gtk.set_application_name(Dialpad.__pretty_app_name__)
if optparse is not None:
parser = optparse.OptionParser()