X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Fdc_glade.py;h=33ad67aa4e44a31f77a6d52dca71b18d7cc7cbe2;hb=8045ca5f903a95f5ec09f1d82bd35f0b18974245;hp=14b6db5e4712b5ef7e368685c44807af66cf25ce;hpb=c7301600ffd56e63f6c70e31b1a4d7b85435743b;p=gc-dialer diff --git a/src/dc_glade.py b/src/dc_glade.py index 14b6db5..33ad67a 100755 --- a/src/dc_glade.py +++ b/src/dc_glade.py @@ -1,7 +1,7 @@ #!/usr/bin/python2.5 """ -DialCentral - Front end for Google's Grand Central service. +DialCentral - Front end for Google's GoogleVoice service. Copyright (C) 2008 Mark Bergman bergman AT merctech DOT com This library is free software; you can redistribute it and/or @@ -17,14 +17,6 @@ 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 - -@todo Figure out how to integrate with the Maemo contacts app -@todo Look into an actor system -@bug Session timeouts are bad, possible solutions: - @li For every X minutes, if logged in, attempt login - @li Restructure so code handling login/dial/sms is beneath everything else and login attempts are made if those fail -@todo Can't text from dialpad (so can't do any arbitrary number texts) -@todo Add logging support to make debugging issues for people a lot easier """ @@ -37,24 +29,23 @@ import threading import base64 import ConfigParser import itertools -import warnings +import logging import gtk import gtk.glade -try: - import hildon -except ImportError: - hildon = None - import constants +import hildonize import gtk_toolbox +_moduleLogger = logging.getLogger("dc_glade") + + def getmtime_nothrow(path): try: return os.path.getmtime(path) - except StandardError: + except Exception: return 0 @@ -82,9 +73,8 @@ class Dialcentral(object): ACCOUNT_TAB = 4 NULL_BACKEND = 0 - GC_BACKEND = 1 GV_BACKEND = 2 - BACKENDS = (NULL_BACKEND, GC_BACKEND, GV_BACKEND) + BACKENDS = (NULL_BACKEND, GV_BACKEND) def __init__(self): self._initDone = False @@ -94,7 +84,7 @@ class Dialcentral(object): self._credentials = ("", "") self._selectedBackendId = self.NULL_BACKEND - self._defaultBackendId = self.GC_BACKEND + self._defaultBackendId = self.GV_BACKEND self._phoneBackends = None self._dialpads = None self._accountViews = None @@ -119,45 +109,57 @@ class Dialcentral(object): self._errorDisplay = gtk_toolbox.ErrorDisplay(self._widgetTree) self._credentialsDialog = gtk_toolbox.LoginWindow(self._widgetTree) - self._app = None self._isFullScreen = False - if hildon is not None: - self._app = hildon.Program() - oldWindow = self._window - self._window = hildon.Window() - oldWindow.get_child().reparent(self._window) - self._app.add_window(self._window) - - try: - self._widgetTree.get_widget("usernameentry").set_property('hildon-input-mode', 7) - self._widgetTree.get_widget("passwordentry").set_property('hildon-input-mode', 7|(1 << 29)) - self._widgetTree.get_widget("callbackcombo").get_child().set_property('hildon-input-mode', (1 << 4)) - except TypeError, e: - warnings.warn(e.message) - hildon.hildon_helper_set_thumb_scrollbar(self._widgetTree.get_widget('recent_scrolledwindow'), True) - hildon.hildon_helper_set_thumb_scrollbar(self._widgetTree.get_widget('message_scrolledwindow'), True) - hildon.hildon_helper_set_thumb_scrollbar(self._widgetTree.get_widget('contacts_scrolledwindow'), True) - - gtkMenu = self._widgetTree.get_widget("dialpad_menubar") - menu = gtk.Menu() - for child in gtkMenu.get_children(): - child.reparent(menu) - self._window.set_menu(menu) - gtkMenu.destroy() - - self._window.connect("key-press-event", self._on_key_press) - self._window.connect("window-state-event", self._on_window_state_change) - else: - pass # warnings.warn("No Hildon", UserWarning, 2) + self._app = hildonize.get_app_class()() + self._window = hildonize.hildonize_window(self._app, self._window) + hildonize.hildonize_text_entry(self._widgetTree.get_widget("usernameentry")) + hildonize.hildonize_password_entry(self._widgetTree.get_widget("passwordentry")) + + for scrollingWidgetName in ( + 'recent_scrolledwindow', + 'message_scrolledwindow', + 'contacts_scrolledwindow', + "smsMessages_scrolledwindow", + ): + scrollingWidget = self._widgetTree.get_widget(scrollingWidgetName) + assert scrollingWidget is not None, scrollingWidgetName + hildonize.hildonize_scrollwindow(scrollingWidget) + for scrollingWidgetName in ( + "smsMessage_scrolledEntry", + ): + scrollingWidget = self._widgetTree.get_widget(scrollingWidgetName) + assert scrollingWidget is not None, scrollingWidgetName + hildonize.hildonize_scrollwindow_with_viewport(scrollingWidget) + + for buttonName in ( + "back", + "addressbookSelectButton", + "sendSmsButton", + "dialButton", + "selectButton", + "cancelSmsButton", + "callbackSelectButton", + "minutesEntryButton", + "clearcookies", + "phoneTypeSelection", + ): + button = self._widgetTree.get_widget(buttonName) + assert button is not None, buttonName + hildonize.set_button_thumb_selectable(button) + + replacementButtons = [gtk.Button("Test")] + menu = hildonize.hildonize_menu( + self._window, + self._widgetTree.get_widget("dialpad_menubar"), + replacementButtons + ) - # If under hildon, rely on the application name being shown - if hildon is None: - self._window.set_title("%s" % constants.__pretty_app_name__) + self._window.connect("key-press-event", self._on_key_press) + self._window.connect("window-state-event", self._on_window_state_change) + if not hildonize.IS_HILDON_SUPPORTED: + _moduleLogger.warning("No hildonization support") - callbackMapping = { - "on_dialpad_quit": self._on_close, - } - self._widgetTree.signal_autoconnect(callbackMapping) + hildonize.set_application_title(self._window, "%s" % constants.__pretty_app_name__) self._window.connect("destroy", self._on_close) self._window.set_default_size(800, 300) @@ -165,7 +167,7 @@ class Dialcentral(object): self._loginSink = gtk_toolbox.threaded_stage( gtk_toolbox.comap( - self.attempt_login, + self._attempt_login, gtk_toolbox.null_sink(), ) ) @@ -178,8 +180,8 @@ class Dialcentral(object): """ If something can be done after the UI loads, push it here so it's not blocking the UI """ + # Barebones UI handlers try: - # Barebones UI handlers import null_backend import null_views @@ -196,11 +198,15 @@ class Dialcentral(object): self._recentViews[self._selectedBackendId].enable() self._messagesViews[self._selectedBackendId].enable() self._contactsViews[self._selectedBackendId].enable() + except Exception, e: + with gtk_toolbox.gtk_lock(): + self._errorDisplay.push_exception() - # Setup maemo specifics + # Setup maemo specifics + try: try: import osso - except ImportError: + except (ImportError, OSError): osso = None self._osso = None if osso is not None: @@ -208,22 +214,31 @@ class Dialcentral(object): device = osso.DeviceState(self._osso) device.set_device_state_callback(self._on_device_state_change, 0) else: - pass # warnings.warn("No OSSO", UserWarning, 2) + _moduleLogger.warning("No device state support") try: import alarm_handler self._alarmHandler = alarm_handler.AlarmHandler() - except ImportError: + except (ImportError, OSError): alarm_handler = None - if hildon is not None: - import led_handler - self._ledHandler = led_handler.LedHandler() - self._ledHandler.off() + except Exception: + with gtk_toolbox.gtk_lock(): + self._errorDisplay.push_exception() + alarm_handler = None + _moduleLogger.warning("No notification support") + if hildonize.IS_HILDON_SUPPORTED: + try: + import led_handler + self._ledHandler = led_handler.LedHandler() + except Exception, e: + _moduleLogger.exception('LED Handling failed: "%s"' % str(e)) + self._ledHandler = None + else: + self._ledHandler = None - # Setup maemo specifics try: import conic - except ImportError: + except (ImportError, OSError): conic = None self._connection = None if conic is not None: @@ -231,98 +246,81 @@ class Dialcentral(object): self._connection.connect("connection-event", self._on_connection_change, constants.__app_magic__) self._connection.request_connection(conic.CONNECT_FLAG_NONE) else: - pass # warnings.warn("No Internet Connectivity API ", UserWarning) + _moduleLogger.warning("No connection support") + except Exception, e: + with gtk_toolbox.gtk_lock(): + self._errorDisplay.push_exception() - # Setup costly backends + # Setup costly backends + try: import gv_backend - import gc_backend import file_backend - import evo_backend - import gc_views + import gv_views try: os.makedirs(constants._data_path_) except OSError, e: if e.errno != 17: raise - gcCookiePath = os.path.join(constants._data_path_, "gc_cookies.txt") gvCookiePath = os.path.join(constants._data_path_, "gv_cookies.txt") - self._defaultBackendId = self._guess_preferred_backend(( - (self.GC_BACKEND, gcCookiePath), - (self.GV_BACKEND, gvCookiePath), - )) self._phoneBackends.update({ - self.GC_BACKEND: gc_backend.GCDialer(gcCookiePath), self.GV_BACKEND: gv_backend.GVDialer(gvCookiePath), }) with gtk_toolbox.gtk_lock(): - unifiedDialpad = gc_views.Dialpad(self._widgetTree, self._errorDisplay) - unifiedDialpad.set_number("") + unifiedDialpad = gv_views.Dialpad(self._widgetTree, self._errorDisplay) self._dialpads.update({ - self.GC_BACKEND: unifiedDialpad, self.GV_BACKEND: unifiedDialpad, }) self._accountViews.update({ - self.GC_BACKEND: gc_views.AccountInfo( - self._widgetTree, self._phoneBackends[self.GC_BACKEND], None, self._errorDisplay - ), - self.GV_BACKEND: gc_views.AccountInfo( + self.GV_BACKEND: gv_views.AccountInfo( self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._alarmHandler, self._errorDisplay ), }) - self._accountViews[self.GC_BACKEND].save_everything = lambda *args: None self._accountViews[self.GV_BACKEND].save_everything = self._save_settings self._recentViews.update({ - self.GC_BACKEND: gc_views.RecentCallsView( - self._widgetTree, self._phoneBackends[self.GC_BACKEND], self._errorDisplay - ), - self.GV_BACKEND: gc_views.RecentCallsView( + self.GV_BACKEND: gv_views.RecentCallsView( self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._errorDisplay ), }) self._messagesViews.update({ - self.GC_BACKEND: null_views.MessagesView(self._widgetTree), - self.GV_BACKEND: gc_views.MessagesView( + self.GV_BACKEND: gv_views.MessagesView( self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._errorDisplay ), }) self._contactsViews.update({ - self.GC_BACKEND: gc_views.ContactsView( - self._widgetTree, self._phoneBackends[self.GC_BACKEND], self._errorDisplay - ), - self.GV_BACKEND: gc_views.ContactsView( + self.GV_BACKEND: gv_views.ContactsView( self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._errorDisplay ), }) - evoBackend = evo_backend.EvolutionAddressBook() fsContactsPath = os.path.join(constants._data_path_, "contacts") fileBackend = file_backend.FilesystemAddressBookFactory(fsContactsPath) - for backendId in (self.GV_BACKEND, self.GC_BACKEND): - self._dialpads[backendId].number_selected = self._select_action - self._recentViews[backendId].number_selected = self._select_action - self._messagesViews[backendId].number_selected = self._select_action - self._contactsViews[backendId].number_selected = self._select_action - - addressBooks = [ - self._phoneBackends[backendId], - evoBackend, - fileBackend, - ] - mergedBook = gc_views.MergedAddressBook(addressBooks, gc_views.MergedAddressBook.advanced_lastname_sorter) - self._contactsViews[backendId].append(mergedBook) - self._contactsViews[backendId].extend(addressBooks) - self._contactsViews[backendId].open_addressbook(*self._contactsViews[backendId].get_addressbooks().next()[0][0:2]) + + self._dialpads[self.GV_BACKEND].number_selected = self._select_action + self._recentViews[self.GV_BACKEND].number_selected = self._select_action + self._messagesViews[self.GV_BACKEND].number_selected = self._select_action + self._contactsViews[self.GV_BACKEND].number_selected = self._select_action + + addressBooks = [ + self._phoneBackends[self.GV_BACKEND], + fileBackend, + ] + mergedBook = gv_views.MergedAddressBook(addressBooks, gv_views.MergedAddressBook.advanced_lastname_sorter) + self._contactsViews[self.GV_BACKEND].append(mergedBook) + self._contactsViews[self.GV_BACKEND].extend(addressBooks) + self._contactsViews[self.GV_BACKEND].open_addressbook(*self._contactsViews[self.GV_BACKEND].get_addressbooks().next()[0][0:2]) callbackMapping = { "on_paste": self._on_paste, "on_refresh": self._on_menu_refresh, "on_clearcookies_clicked": self._on_clearcookies_clicked, - "on_notebook_switch_page": self._on_notebook_switch_page, "on_about_activate": self._on_about_activate, } - self._widgetTree.signal_autoconnect(callbackMapping) + if hildonize.GTK_MENU_USED: + self._widgetTree.signal_autoconnect(callbackMapping) + self._notebook.connect("switch-page", self._on_notebook_switch_page) + self._widgetTree.get_widget("clearcookies").connect("clicked", self._on_clearcookies_clicked) with gtk_toolbox.gtk_lock(): self._originalCurrentLabels = [ @@ -342,16 +340,17 @@ class Dialcentral(object): config.read(constants._user_settings_) with gtk_toolbox.gtk_lock(): self.load_settings(config) - - self._spawn_attempt_login(2) except Exception, e: with gtk_toolbox.gtk_lock(): self._errorDisplay.push_exception() + finally: + self._spawn_attempt_login(2) - def attempt_login(self, numOfAttempts = 10, force = False): - """ - @todo Handle user notification better like attempting to login and failed login + def _spawn_attempt_login(self, *args): + self._loginSink.send(args) + def _attempt_login(self, numOfAttempts = 10, force = False): + """ @note This must be run outside of the UI lock """ try: @@ -361,25 +360,31 @@ class Dialcentral(object): serviceId = self.NULL_BACKEND loggedIn = False if not force: + with gtk_toolbox.gtk_lock(): + banner = hildonize.show_busy_banner_start(self._window, "Logging In...") try: self.refresh_session() serviceId = self._defaultBackendId loggedIn = True - except StandardError, e: - warnings.warn('Session refresh failed with the following message "%s"' % e.message, UserWarning, 2) + except Exception, e: + _moduleLogger.exception('Session refresh failed with the following message "%s"' % str(e)) + finally: + with gtk_toolbox.gtk_lock(): + hildonize.show_busy_banner_end(banner) if not loggedIn: loggedIn, serviceId = self._login_by_user(numOfAttempts) with gtk_toolbox.gtk_lock(): self._change_loggedin_status(serviceId) - except StandardError, e: + if loggedIn: + hildonize.show_information_banner(self._window, "Logged In") + else: + hildonize.show_information_banner(self._window, "Login Failed") + except Exception, e: with gtk_toolbox.gtk_lock(): self._errorDisplay.push_exception() - def _spawn_attempt_login(self, *args): - self._loginSink.send(args) - def refresh_session(self): """ @note Thread agnostic @@ -401,10 +406,7 @@ class Dialcentral(object): """ loggedIn = self._phoneBackends[self._defaultBackendId].is_authed() if loggedIn: - warnings.warn( - "Logged into %r through cookies" % self._phoneBackends[self._defaultBackendId], - UserWarning, 2 - ) + _moduleLogger.info("Logged into %r through cookies" % self._phoneBackends[self._defaultBackendId]) return loggedIn def _login_by_settings(self): @@ -415,10 +417,7 @@ class Dialcentral(object): loggedIn = self._phoneBackends[self._defaultBackendId].login(username, password) if loggedIn: self._credentials = username, password - warnings.warn( - "Logged into %r through settings" % self._phoneBackends[self._defaultBackendId], - UserWarning, 2 - ) + _moduleLogger.info("Logged into %r through settings" % self._phoneBackends[self._defaultBackendId]) return loggedIn def _login_by_user(self, numOfAttempts): @@ -426,30 +425,32 @@ class Dialcentral(object): @note This must be run outside of the UI lock """ loggedIn, (username, password) = False, self._credentials - tmpServiceId = self.NULL_BACKEND + tmpServiceId = self.GV_BACKEND for attemptCount in xrange(numOfAttempts): if loggedIn: break - availableServices = ( - (self.GV_BACKEND, "Google Voice"), - (self.GC_BACKEND, "Grand Central"), - ) with gtk_toolbox.gtk_lock(): - credentials = self._credentialsDialog.request_credentials_from( - availableServices, defaultCredentials = self._credentials + credentials = self._credentialsDialog.request_credentials( + defaultCredentials = self._credentials ) - tmpServiceId, username, password = credentials - loggedIn = self._phoneBackends[tmpServiceId].login(username, password) + if not self._phoneBackends[tmpServiceId].get_callback_number(): + # subtle reminder to the users to configure things + self._notebook.set_current_page(self.ACCOUNT_TAB) + banner = hildonize.show_busy_banner_start(self._window, "Logging In...") + try: + username, password = credentials + loggedIn = self._phoneBackends[tmpServiceId].login(username, password) + finally: + with gtk_toolbox.gtk_lock(): + hildonize.show_busy_banner_end(banner) if loggedIn: serviceId = tmpServiceId self._credentials = username, password - warnings.warn( - "Logged into %r through user request" % self._phoneBackends[serviceId], - UserWarning, 2 - ) + _moduleLogger.info("Logged into %r through user request" % self._phoneBackends[serviceId]) else: serviceId = self.NULL_BACKEND + self._notebook.set_current_page(self.ACCOUNT_TAB) return loggedIn, serviceId @@ -484,16 +485,18 @@ class Dialcentral(object): if self._phoneBackends[self._selectedBackendId].get_callback_number() is None: self._phoneBackends[self._selectedBackendId].set_sane_callback() - self._accountViews[self._selectedBackendId].update() self._selectedBackendId = newStatus + self._accountViews[self._selectedBackendId].update() + self._refresh_active_tab() + def load_settings(self, config): """ @note UI Thread """ try: - self._defaultBackendId = int(config.get(constants.__pretty_app_name__, "active")) + self._defaultBackendId = config.getint(constants.__pretty_app_name__, "active") blobs = ( config.get(constants.__pretty_app_name__, "bin_blob_%i" % i) for i in xrange(len(self._credentials)) @@ -507,20 +510,18 @@ class Dialcentral(object): if self._alarmHandler is not None: self._alarmHandler.load_settings(config, "alarm") except ConfigParser.NoOptionError, e: - warnings.warn( + _moduleLogger.exception( "Settings file %s is missing section %s" % ( constants._user_settings_, e.section, ), - stacklevel=2 ) except ConfigParser.NoSectionError, e: - warnings.warn( + _moduleLogger.exception( "Settings file %s is missing section %s" % ( constants._user_settings_, e.section, ), - stacklevel=2 ) for backendId, view in itertools.chain( @@ -534,28 +535,48 @@ class Dialcentral(object): try: view.load_settings(config, sectionName) except ConfigParser.NoOptionError, e: - warnings.warn( + _moduleLogger.exception( "Settings file %s is missing section %s" % ( constants._user_settings_, e.section, ), - stacklevel=2 ) except ConfigParser.NoSectionError, e: - warnings.warn( + _moduleLogger.exception( "Settings file %s is missing section %s" % ( constants._user_settings_, e.section, ), - stacklevel=2 ) + try: + previousOrientation = config.getint(constants.__pretty_app_name__, "orientation") + if previousOrientation == gtk.ORIENTATION_HORIZONTAL: + hildonize.window_to_landscape(self._window) + elif previousOrientation == gtk.ORIENTATION_VERTICAL: + hildonize.window_to_portrait(self._window) + except ConfigParser.NoOptionError, e: + _moduleLogger.exception( + "Settings file %s is missing section %s" % ( + constants._user_settings_, + e.section, + ), + ) + except ConfigParser.NoSectionError, e: + _moduleLogger.exception( + "Settings file %s is missing section %s" % ( + constants._user_settings_, + e.section, + ), + ) + def save_settings(self, config): """ @note Thread Agnostic """ config.add_section(constants.__pretty_app_name__) config.set(constants.__pretty_app_name__, "active", str(self._selectedBackendId)) + config.set(constants.__pretty_app_name__, "orientation", str(int(gtk_toolbox.get_screen_orientation()))) for i, value in enumerate(self._credentials): blob = base64.b64encode(value) config.set(constants.__pretty_app_name__, "bin_blob_%i" % i, blob) @@ -574,14 +595,6 @@ class Dialcentral(object): config.add_section(sectionName) view.save_settings(config, sectionName) - def _guess_preferred_backend(self, backendAndCookiePaths): - modTimeAndPath = [ - (getmtime_nothrow(path), backendId, path) - for backendId, path in backendAndCookiePaths - ] - modTimeAndPath.sort() - return modTimeAndPath[-1][1] - def _save_settings(self): """ @note Thread Agnostic @@ -592,9 +605,6 @@ class Dialcentral(object): config.write(configFile) def _refresh_active_tab(self): - if self._ledHandler is not None: - self._ledHandler.off() - pageIndex = self._notebook.get_current_page() if pageIndex == self.CONTACTS_TAB: self._contactsViews[self._selectedBackendId].update(force=True) @@ -603,6 +613,10 @@ class Dialcentral(object): elif pageIndex == self.MESSAGES_TAB: self._messagesViews[self._selectedBackendId].update(force=True) + if pageIndex in (self.RECENT_TAB, self.MESSAGES_TAB): + if self._ledHandler is not None: + self._ledHandler.off() + def _on_close(self, *args, **kwds): try: if self._osso is not None: @@ -620,161 +634,217 @@ class Dialcentral(object): @note Hildon specific """ - if memory_low: - for backendId in self.BACKENDS: - self._phoneBackends[backendId].clear_caches() - self._contactsViews[self._selectedBackendId].clear_caches() - gc.collect() + try: + if memory_low: + for backendId in self.BACKENDS: + self._phoneBackends[backendId].clear_caches() + self._contactsViews[self._selectedBackendId].clear_caches() + gc.collect() - if save_unsaved_data or shutdown: - self._save_settings() + if save_unsaved_data or shutdown: + self._save_settings() + except Exception, e: + self._errorDisplay.push_exception() def _on_connection_change(self, connection, event, magicIdentifier): """ @note Hildon specific """ - import conic - - status = event.get_status() - error = event.get_error() - iap_id = event.get_iap_id() - bearer = event.get_bearer_type() - - if status == conic.STATUS_CONNECTED: - if self._initDone: - self._spawn_attempt_login(2) - elif status == conic.STATUS_DISCONNECTED: - if self._initDone: - self._defaultBackendId = self._selectedBackendId - self._change_loggedin_status(self.NULL_BACKEND) + try: + import conic + + status = event.get_status() + error = event.get_error() + iap_id = event.get_iap_id() + bearer = event.get_bearer_type() + + if status == conic.STATUS_CONNECTED: + if self._initDone: + self._spawn_attempt_login(2) + elif status == conic.STATUS_DISCONNECTED: + if self._initDone: + self._defaultBackendId = self._selectedBackendId + self._change_loggedin_status(self.NULL_BACKEND) + except Exception, e: + self._errorDisplay.push_exception() def _on_window_state_change(self, widget, event, *args): """ @note Hildon specific """ - if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN: - self._isFullScreen = True - else: - self._isFullScreen = False + try: + if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN: + self._isFullScreen = True + else: + self._isFullScreen = False + except Exception, e: + self._errorDisplay.push_exception() def _on_key_press(self, widget, event, *args): """ @note Hildon specific """ - if event.keyval == gtk.keysyms.F6: - if self._isFullScreen: - self._window.unfullscreen() - else: - self._window.fullscreen() + RETURN_TYPES = (gtk.keysyms.Return, gtk.keysyms.ISO_Enter, gtk.keysyms.KP_Enter) + try: + if ( + event.keyval == gtk.keysyms.F6 or + event.keyval in RETURN_TYPES and event.get_state() & gtk.gdk.CONTROL_MASK + ): + if self._isFullScreen: + self._window.unfullscreen() + else: + self._window.fullscreen() + except Exception, e: + self._errorDisplay.push_exception() def _on_clearcookies_clicked(self, *args): - self._phoneBackends[self._selectedBackendId].logout() - self._accountViews[self._selectedBackendId].clear() - self._recentViews[self._selectedBackendId].clear() - self._messagesViews[self._selectedBackendId].clear() - self._contactsViews[self._selectedBackendId].clear() - self._change_loggedin_status(self.NULL_BACKEND) - - self._spawn_attempt_login(2, True) + try: + self._phoneBackends[self._selectedBackendId].logout() + self._accountViews[self._selectedBackendId].clear() + self._recentViews[self._selectedBackendId].clear() + self._messagesViews[self._selectedBackendId].clear() + self._contactsViews[self._selectedBackendId].clear() + self._change_loggedin_status(self.NULL_BACKEND) + + self._spawn_attempt_login(2, True) + except Exception, e: + self._errorDisplay.push_exception() def _on_notebook_switch_page(self, notebook, page, pageIndex): - self._reset_tab_refresh() - if pageIndex == self.RECENT_TAB: - self._recentViews[self._selectedBackendId].update() - elif pageIndex == self.MESSAGES_TAB: - self._messagesViews[self._selectedBackendId].update() - elif pageIndex == self.CONTACTS_TAB: - self._contactsViews[self._selectedBackendId].update() - elif pageIndex == self.ACCOUNT_TAB: - self._accountViews[self._selectedBackendId].update() + try: + self._reset_tab_refresh() + + didRecentUpdate = False + didMessagesUpdate = False + + if pageIndex == self.RECENT_TAB: + didRecentUpdate = self._recentViews[self._selectedBackendId].update() + elif pageIndex == self.MESSAGES_TAB: + didMessagesUpdate = self._messagesViews[self._selectedBackendId].update() + elif pageIndex == self.CONTACTS_TAB: + self._contactsViews[self._selectedBackendId].update() + elif pageIndex == self.ACCOUNT_TAB: + self._accountViews[self._selectedBackendId].update() + + if didRecentUpdate or didMessagesUpdate: + if self._ledHandler is not None: + self._ledHandler.off() + except Exception, e: + self._errorDisplay.push_exception() def _set_tab_refresh(self, *args): - pageIndex = self._notebook.get_current_page() - child = self._notebook.get_nth_page(pageIndex) - self._notebook.get_tab_label(child).set_text("Refresh?") + try: + pageIndex = self._notebook.get_current_page() + child = self._notebook.get_nth_page(pageIndex) + self._notebook.get_tab_label(child).set_text("Refresh?") + except Exception, e: + self._errorDisplay.push_exception() return False def _reset_tab_refresh(self, *args): - pageIndex = self._notebook.get_current_page() - child = self._notebook.get_nth_page(pageIndex) - self._notebook.get_tab_label(child).set_text(self._originalCurrentLabels[pageIndex]) + try: + pageIndex = self._notebook.get_current_page() + child = self._notebook.get_nth_page(pageIndex) + self._notebook.get_tab_label(child).set_text(self._originalCurrentLabels[pageIndex]) + except Exception, e: + self._errorDisplay.push_exception() return False def _on_tab_refresh(self, *args): - self._refresh_active_tab() - self._reset_tab_refresh() + try: + self._refresh_active_tab() + self._reset_tab_refresh() + except Exception, e: + self._errorDisplay.push_exception() return False def _on_sms_clicked(self, number, message): - assert number, "No number specified" - assert message, "Empty message" try: - loggedIn = self._phoneBackends[self._selectedBackendId].is_authed() - except StandardError, e: - loggedIn = False - self._errorDisplay.push_exception() - return + assert number, "No number specified" + assert message, "Empty message" + try: + loggedIn = self._phoneBackends[self._selectedBackendId].is_authed() + except Exception, e: + loggedIn = False + self._errorDisplay.push_exception() + return - if not loggedIn: - self._errorDisplay.push_message( - "Backend link with grandcentral is not working, please try again" - ) - return + if not loggedIn: + self._errorDisplay.push_message( + "Backend link with GoogleVoice is not working, please try again" + ) + return - dialed = False - try: - self._phoneBackends[self._selectedBackendId].send_sms(number, message) - dialed = True - except StandardError, e: - self._errorDisplay.push_exception() - except ValueError, e: + dialed = False + try: + self._phoneBackends[self._selectedBackendId].send_sms(number, message) + hildonize.show_information_banner(self._window, "Sending to %s" % number) + dialed = True + except Exception, e: + self._errorDisplay.push_exception() + + if dialed: + self._dialpads[self._selectedBackendId].clear() + except Exception, e: self._errorDisplay.push_exception() def _on_dial_clicked(self, number): - assert number, "No number to call" try: - loggedIn = self._phoneBackends[self._selectedBackendId].is_authed() - except StandardError, e: - loggedIn = False - self._errorDisplay.push_exception() - return + assert number, "No number to call" + try: + loggedIn = self._phoneBackends[self._selectedBackendId].is_authed() + except Exception, e: + loggedIn = False + self._errorDisplay.push_exception() + return - if not loggedIn: - self._errorDisplay.push_message( - "Backend link with grandcentral is not working, please try again" - ) - return + if not loggedIn: + self._errorDisplay.push_message( + "Backend link with GoogleVoice is not working, please try again" + ) + return - dialed = False - try: - assert self._phoneBackends[self._selectedBackendId].get_callback_number() != "", "No callback number specified" - self._phoneBackends[self._selectedBackendId].dial(number) - dialed = True - except StandardError, e: - self._errorDisplay.push_exception() - except ValueError, e: - self._errorDisplay.push_exception() + dialed = False + try: + assert self._phoneBackends[self._selectedBackendId].get_callback_number() != "", "No callback number specified" + self._phoneBackends[self._selectedBackendId].dial(number) + hildonize.show_information_banner(self._window, "Calling %s" % number) + dialed = True + except Exception, e: + self._errorDisplay.push_exception() - if dialed: - self._dialpads[self._selectedBackendId].clear() + if dialed: + self._dialpads[self._selectedBackendId].clear() + except Exception, e: + self._errorDisplay.push_exception() def _on_menu_refresh(self, *args): - self._refresh_active_tab() + try: + self._refresh_active_tab() + except Exception, e: + self._errorDisplay.push_exception() def _on_paste(self, *args): - contents = self._clipboard.wait_for_text() - self._dialpads[self._selectedBackendId].set_number(contents) + try: + contents = self._clipboard.wait_for_text() + if contents is not None: + self._dialpads[self._selectedBackendId].set_number(contents) + except Exception, e: + self._errorDisplay.push_exception() def _on_about_activate(self, *args): - dlg = gtk.AboutDialog() - dlg.set_name(constants.__pretty_app_name__) - dlg.set_version(constants.__version__) - dlg.set_copyright("Copyright 2008 - LGPL") - dlg.set_comments("Dialcentral is a touch screen enhanced interface to your GoogleVoice/Grandcentral account. This application is not affiliated with Google in any way") - dlg.set_website("http://gc-dialer.garage.maemo.org/") - dlg.set_authors(["", "Eric Warnke ", "Ed Page "]) - dlg.run() - dlg.destroy() + try: + dlg = gtk.AboutDialog() + dlg.set_name(constants.__pretty_app_name__) + dlg.set_version("%s-%d" % (constants.__version__, constants.__build__)) + dlg.set_copyright("Copyright 2008 - LGPL") + dlg.set_comments("Dialcentral is a touch screen enhanced interface to your GoogleVoice account. This application is not affiliated with Google in any way") + dlg.set_website("http://gc-dialer.garage.maemo.org/") + dlg.set_authors(["", "Eric Warnke ", "Ed Page "]) + dlg.run() + dlg.destroy() + except Exception, e: + self._errorDisplay.push_exception() def run_doctest(): @@ -790,13 +860,13 @@ def run_doctest(): def run_dialpad(): _lock_file = os.path.join(constants._data_path_, ".lock") - with gtk_toolbox.flock(_lock_file, 0): - gtk.gdk.threads_init() + #with gtk_toolbox.flock(_lock_file, 0): + gtk.gdk.threads_init() - if hildon is not None: - gtk.set_application_name(constants.__pretty_app_name__) - handle = Dialcentral() - gtk.main() + if hildonize.IS_HILDON_SUPPORTED: + gtk.set_application_name(constants.__pretty_app_name__) + handle = Dialcentral() + gtk.main() class DummyOptions(object): @@ -806,21 +876,25 @@ class DummyOptions(object): if __name__ == "__main__": - if len(sys.argv) > 1: - try: - import optparse - except ImportError: - optparse = None - - if optparse is not None: - parser = optparse.OptionParser() - parser.add_option("-t", "--test", action="store_true", dest="test", help="Run tests") - (commandOptions, commandArgs) = parser.parse_args() - else: - commandOptions = DummyOptions() - commandArgs = [] + logging.basicConfig(level=logging.DEBUG) + try: + if len(sys.argv) > 1: + try: + import optparse + except ImportError: + optparse = None - if commandOptions.test: - run_doctest() - else: - run_dialpad() + if optparse is not None: + parser = optparse.OptionParser() + parser.add_option("-t", "--test", action="store_true", dest="test", help="Run tests") + (commandOptions, commandArgs) = parser.parse_args() + else: + commandOptions = DummyOptions() + commandArgs = [] + + if commandOptions.test: + run_doctest() + else: + run_dialpad() + finally: + logging.shutdown()