X-Git-Url: http://git.maemo.org/git/?p=gc-dialer;a=blobdiff_plain;f=src%2Fdc_glade.py;h=2c1563e1c2fe00667501420cc7a3fcf5f51a7a28;hp=4d16c74e5e4abb464f022154a1343c498aa10a9a;hb=0320d6d2086ce89fe554d8f902531f5b00dbec94;hpb=90b82da9a8a2a613a1e426bc77fd47aa993f51d8 diff --git a/src/dc_glade.py b/src/dc_glade.py index 4d16c74..2c1563e 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 @@ -29,6 +29,7 @@ import threading import base64 import ConfigParser import itertools +import shutil import logging import gtk @@ -39,10 +40,14 @@ import hildonize import gtk_toolbox +_moduleLogger = logging.getLogger("dc_glade") +PROFILE_STARTUP = False + + def getmtime_nothrow(path): try: return os.path.getmtime(path) - except StandardError: + except Exception: return 0 @@ -70,6 +75,7 @@ class Dialcentral(object): ACCOUNT_TAB = 4 NULL_BACKEND = 0 + # 1 Was GrandCentral support so the gap was maintained for compatibility GV_BACKEND = 2 BACKENDS = (NULL_BACKEND, GV_BACKEND) @@ -77,6 +83,7 @@ class Dialcentral(object): self._initDone = False self._connection = None self._osso = None + self._deviceState = None self._clipboard = gtk.clipboard_get() self._credentials = ("", "") @@ -86,11 +93,12 @@ class Dialcentral(object): self._dialpads = None self._accountViews = None self._messagesViews = None - self._recentViews = None + self._historyViews = None self._contactsViews = None self._alarmHandler = None self._ledHandler = None self._originalCurrentLabels = [] + self._fsContactsPath = os.path.join(constants._data_path_, "contacts") for path in self._glade_files: if os.path.isfile(path): @@ -111,34 +119,63 @@ class Dialcentral(object): 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")) - hildonize.hildonize_combo_entry(self._widgetTree.get_widget("callbackcombo").get_child()) - for scrollingWidget in ( - 'recent_scrolledwindow', + for scrollingWidgetName in ( + 'history_scrolledwindow', 'message_scrolledwindow', 'contacts_scrolledwindow', - "phoneSelectionMessage_scrolledwindow", - "phonetypes_scrolledwindow", - "smsMessage_scrolledwindow", + "smsMessages_scrolledwindow", + ): + scrollingWidget = self._widgetTree.get_widget(scrollingWidgetName) + assert scrollingWidget is not None, scrollingWidgetName + hildonize.hildonize_scrollwindow(scrollingWidget) + for scrollingWidgetName in ( "smsMessage_scrolledEntry", ): - hildonize.set_thumb_scrollbar(self._widgetTree.get_widget(scrollingWidget)) + 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", + "cancelSmsButton", + "callbackSelectButton", + "minutesEntryButton", + "clearcookies", + "phoneTypeSelection", + ): + button = self._widgetTree.get_widget(buttonName) + assert button is not None, buttonName + hildonize.set_button_thumb_selectable(button) - hildonize.hildonize_menu(self._window, self._widgetTree.get_widget("dialpad_menubar")) + menu = hildonize.hildonize_menu( + self._window, + self._widgetTree.get_widget("dialpad_menubar"), + ) + if not hildonize.GTK_MENU_USED: + button = gtk.Button("New Login") + button.connect("clicked", self._on_clearcookies_clicked) + menu.append(button) - if hildonize.IS_HILDON: - self._window.connect("key-press-event", self._on_key_press) - self._window.connect("window-state-event", self._on_window_state_change) - else: - logging.warning("No hildonization support") + button = gtk.Button("Import Contacts") + button.connect("clicked", self._on_contact_import) + menu.append(button) + button = gtk.Button("Refresh") + button.connect("clicked", self._on_menu_refresh) + menu.append(button) - hildonize.set_application_title(self._window, "%s" % constants.__pretty_app_name__) + menu.show_all() + + 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) @@ -146,69 +183,86 @@ class Dialcentral(object): self._loginSink = gtk_toolbox.threaded_stage( gtk_toolbox.comap( - self.attempt_login, + self._attempt_login, gtk_toolbox.null_sink(), ) ) - backgroundSetup = threading.Thread(target=self._idle_setup) - backgroundSetup.setDaemon(True) - backgroundSetup.start() + if not PROFILE_STARTUP: + backgroundSetup = threading.Thread(target=self._idle_setup) + backgroundSetup.setDaemon(True) + backgroundSetup.start() + else: + self._idle_setup() def _idle_setup(self): """ 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 + from backends import null_backend import null_views self._phoneBackends = {self.NULL_BACKEND: null_backend.NullDialer()} with gtk_toolbox.gtk_lock(): self._dialpads = {self.NULL_BACKEND: null_views.Dialpad(self._widgetTree)} self._accountViews = {self.NULL_BACKEND: null_views.AccountInfo(self._widgetTree)} - self._recentViews = {self.NULL_BACKEND: null_views.RecentCallsView(self._widgetTree)} + self._historyViews = {self.NULL_BACKEND: null_views.CallHistoryView(self._widgetTree)} self._messagesViews = {self.NULL_BACKEND: null_views.MessagesView(self._widgetTree)} self._contactsViews = {self.NULL_BACKEND: null_views.ContactsView(self._widgetTree)} self._dialpads[self._selectedBackendId].enable() self._accountViews[self._selectedBackendId].enable() - self._recentViews[self._selectedBackendId].enable() + self._historyViews[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 + self._deviceState = None if osso is not None: self._osso = osso.Context(constants.__app_name__, constants.__version__, False) - device = osso.DeviceState(self._osso) - device.set_device_state_callback(self._on_device_state_change, 0) + self._deviceState = osso.DeviceState(self._osso) + self._deviceState.set_device_state_callback(self._on_device_state_change, 0) else: - logging.warning("No device state support") + _moduleLogger.warning("No device state support") try: import alarm_handler - self._alarmHandler = alarm_handler.AlarmHandler() - except ImportError: + if alarm_handler.AlarmHandler is not alarm_handler._NoneAlarmHandler: + self._alarmHandler = alarm_handler.AlarmHandler() + else: + self._alarmHandler = None + except (ImportError, OSError): alarm_handler = None except Exception: with gtk_toolbox.gtk_lock(): self._errorDisplay.push_exception() alarm_handler = None - logging.warning("No notification support") - if hildonize.IS_HILDON: - import led_handler - self._ledHandler = led_handler.LedHandler() + if alarm_handler is 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: @@ -216,12 +270,17 @@ class Dialcentral(object): self._connection.connect("connection-event", self._on_connection_change, constants.__app_magic__) self._connection.request_connection(conic.CONNECT_FLAG_NONE) else: - logging.warning("No connection support") + _moduleLogger.warning("No connection support") + except Exception, e: + with gtk_toolbox.gtk_lock(): + self._errorDisplay.push_exception() - # Setup costly backends - import gv_backend - import file_backend + # Setup costly backends + try: + from backends import gv_backend + from backends import file_backend import gv_views + from backends import merge_backend try: os.makedirs(constants._data_path_) @@ -244,8 +303,8 @@ class Dialcentral(object): ), }) self._accountViews[self.GV_BACKEND].save_everything = self._save_settings - self._recentViews.update({ - self.GV_BACKEND: gv_views.RecentCallsView( + self._historyViews.update({ + self.GV_BACKEND: gv_views.CallHistoryView( self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._errorDisplay ), }) @@ -260,11 +319,10 @@ class Dialcentral(object): ), }) - fsContactsPath = os.path.join(constants._data_path_, "contacts") - fileBackend = file_backend.FilesystemAddressBookFactory(fsContactsPath) + fileBackend = file_backend.FilesystemAddressBookFactory(self._fsContactsPath) self._dialpads[self.GV_BACKEND].number_selected = self._select_action - self._recentViews[self.GV_BACKEND].number_selected = self._select_action + self._historyViews[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 @@ -272,7 +330,7 @@ class Dialcentral(object): self._phoneBackends[self.GV_BACKEND], fileBackend, ] - mergedBook = gv_views.MergedAddressBook(addressBooks, gv_views.MergedAddressBook.advanced_lastname_sorter) + mergedBook = merge_backend.MergedAddressBook(addressBooks, merge_backend.MergedAddressBook.basic_firtname_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]) @@ -281,10 +339,13 @@ class Dialcentral(object): "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, + "on_import": self._on_contact_import, } - 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 = [ @@ -298,50 +359,59 @@ class Dialcentral(object): self._notebookTapHandler.on_holding = self._set_tab_refresh self._notebookTapHandler.on_cancel = self._reset_tab_refresh - self._initDone = True - config = ConfigParser.SafeConfigParser() 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._initDone = True + self._spawn_attempt_login() - 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, force = False): + """ @note This must be run outside of the UI lock """ try: - assert 0 <= numOfAttempts, "That was pointless having 0 or less login attempts" assert self._initDone, "Attempting login before app is fully loaded" serviceId = self.NULL_BACKEND loggedIn = False - if not force: + if not force and self._defaultBackendId != self.NULL_BACKEND: + 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: - logging.exception('Session refresh failed with the following message "%s"' % e.message) + 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) + loggedIn, serviceId = self._login_by_user() 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") + if not self._phoneBackends[self._defaultBackendId].get_callback_number(): + # subtle reminder to the users to configure things + self._notebook.set_current_page(self.ACCOUNT_TAB) + + 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 @@ -361,56 +431,74 @@ class Dialcentral(object): """ @note Thread agnostic """ - loggedIn = self._phoneBackends[self._defaultBackendId].is_authed() + loggedIn = False + + isQuickLoginPossible = self._phoneBackends[self._defaultBackendId].is_quick_login_possible() + if self._credentials != ("", "") and isQuickLoginPossible: + if not loggedIn: + loggedIn = self._phoneBackends[self._defaultBackendId].is_authed() + if loggedIn: - logging.info("Logged into %r through cookies" % self._phoneBackends[self._defaultBackendId]) + _moduleLogger.info("Logged into %r through cookies" % self._phoneBackends[self._defaultBackendId]) + else: + # If the cookies are bad, scratch them completely + self._phoneBackends[self._defaultBackendId].logout() + return loggedIn def _login_by_settings(self): """ @note Thread agnostic """ + if self._credentials == ("", ""): + # Don't bother with the settings if they are blank + return False + username, password = self._credentials loggedIn = self._phoneBackends[self._defaultBackendId].login(username, password) if loggedIn: self._credentials = username, password - logging.info("Logged into %r through settings" % self._phoneBackends[self._defaultBackendId]) + _moduleLogger.info("Logged into %r through settings" % self._phoneBackends[self._defaultBackendId]) return loggedIn - def _login_by_user(self, numOfAttempts): + def _login_by_user(self): """ @note This must be run outside of the UI lock """ loggedIn, (username, password) = False, self._credentials tmpServiceId = self.GV_BACKEND - for attemptCount in xrange(numOfAttempts): - if loggedIn: - break + while not loggedIn: with gtk_toolbox.gtk_lock(): credentials = self._credentialsDialog.request_credentials( defaultCredentials = self._credentials ) - username, password = credentials - loggedIn = self._phoneBackends[tmpServiceId].login(username, password) + 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 - logging.info("Logged into %r through user request" % self._phoneBackends[serviceId]) + _moduleLogger.info("Logged into %r through user request" % self._phoneBackends[serviceId]) else: + # Hint to the user that they are not logged in serviceId = self.NULL_BACKEND + self._notebook.set_current_page(self.ACCOUNT_TAB) return loggedIn, serviceId - def _select_action(self, action, number, message): + def _select_action(self, action, numbers, message): self.refresh_session() - if action == "select": - self._dialpads[self._selectedBackendId].set_number(number) - self._notebook.set_current_page(self.KEYPAD_TAB) - elif action == "dial": + if action == "dial": + assert len(numbers) == 1 + number = numbers[0] self._on_dial_clicked(number) elif action == "sms": - self._on_sms_clicked(number, message) + self._on_sms_clicked(numbers, message) else: assert False, "Unknown action: %s" % action @@ -421,28 +509,30 @@ class Dialcentral(object): self._dialpads[oldStatus].disable() self._accountViews[oldStatus].disable() - self._recentViews[oldStatus].disable() + self._historyViews[oldStatus].disable() self._messagesViews[oldStatus].disable() self._contactsViews[oldStatus].disable() self._dialpads[newStatus].enable() self._accountViews[newStatus].enable() - self._recentViews[newStatus].enable() + self._historyViews[newStatus].enable() self._messagesViews[newStatus].enable() self._contactsViews[newStatus].enable() - 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")) + if not PROFILE_STARTUP: + self._defaultBackendId = config.getint(constants.__pretty_app_name__, "active") + else: + self._defaultBackendId = self.NULL_BACKEND blobs = ( config.get(constants.__pretty_app_name__, "bin_blob_%i" % i) for i in xrange(len(self._credentials)) @@ -455,15 +545,19 @@ class Dialcentral(object): if self._alarmHandler is not None: self._alarmHandler.load_settings(config, "alarm") + + isFullscreen = config.getboolean(constants.__pretty_app_name__, "fullscreen") + if isFullscreen: + self._window.fullscreen() except ConfigParser.NoOptionError, e: - logging.exception( + _moduleLogger.exception( "Settings file %s is missing section %s" % ( constants._user_settings_, e.section, ), ) except ConfigParser.NoSectionError, e: - logging.exception( + _moduleLogger.exception( "Settings file %s is missing section %s" % ( constants._user_settings_, e.section, @@ -474,33 +568,63 @@ class Dialcentral(object): self._dialpads.iteritems(), self._accountViews.iteritems(), self._messagesViews.iteritems(), - self._recentViews.iteritems(), + self._historyViews.iteritems(), self._contactsViews.iteritems(), ): sectionName = "%s - %s" % (backendId, view.name()) try: view.load_settings(config, sectionName) except ConfigParser.NoOptionError, e: - logging.exception( + _moduleLogger.exception( "Settings file %s is missing section %s" % ( constants._user_settings_, e.section, ), ) except ConfigParser.NoSectionError, e: - logging.exception( + _moduleLogger.exception( "Settings file %s is missing section %s" % ( constants._user_settings_, e.section, ), ) + 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 """ + # Because we now only support GVoice, if there are user credentials, + # always assume its using the GVoice backend + if self._credentials[0] and self._credentials[1]: + backend = self.GV_BACKEND + else: + backend = self.NULL_BACKEND + config.add_section(constants.__pretty_app_name__) - config.set(constants.__pretty_app_name__, "active", str(self._selectedBackendId)) + config.set(constants.__pretty_app_name__, "active", str(backend)) + config.set(constants.__pretty_app_name__, "orientation", str(int(gtk_toolbox.get_screen_orientation()))) + config.set(constants.__pretty_app_name__, "fullscreen", str(self._isFullScreen)) for i, value in enumerate(self._credentials): blob = base64.b64encode(value) config.set(constants.__pretty_app_name__, "bin_blob_%i" % i, blob) @@ -512,7 +636,7 @@ class Dialcentral(object): self._dialpads.iteritems(), self._accountViews.iteritems(), self._messagesViews.iteritems(), - self._recentViews.iteritems(), + self._historyViews.iteritems(), self._contactsViews.iteritems(), ): sectionName = "%s - %s" % (backendId, view.name()) @@ -533,7 +657,7 @@ class Dialcentral(object): if pageIndex == self.CONTACTS_TAB: self._contactsViews[self._selectedBackendId].update(force=True) elif pageIndex == self.RECENT_TAB: - self._recentViews[self._selectedBackendId].update(force=True) + self._historyViews[self._selectedBackendId].update(force=True) elif pageIndex == self.MESSAGES_TAB: self._messagesViews[self._selectedBackendId].update(force=True) @@ -541,13 +665,20 @@ class Dialcentral(object): if self._ledHandler is not None: self._ledHandler.off() + @gtk_toolbox.log_exception(_moduleLogger) def _on_close(self, *args, **kwds): try: - if self._osso is not None: - self._osso.close() - if self._initDone: self._save_settings() + + try: + self._deviceState.close() + except AttributeError: + pass # Either None or close was removed (in Fremantle) + try: + self._osso.close() + except AttributeError: + pass # Either None or close was removed (in Fremantle) finally: gtk.main_quit() @@ -558,172 +689,252 @@ 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() + 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() + elif event.keyval == gtk.keysyms.l and event.get_state() & gtk.gdk.CONTROL_MASK: + with open(constants._user_logpath_, "r") as f: + logLines = f.xreadlines() + log = "".join(logLines) + self._clipboard.set_text(str(log)) + elif ( + event.keyval in (gtk.keysyms.w, gtk.keysyms.q) and + event.get_state() & gtk.gdk.CONTROL_MASK + ): + self._window.destroy() + elif event.keyval == gtk.keysyms.r and event.get_state() & gtk.gdk.CONTROL_MASK: + self._refresh_active_tab() + 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._historyViews[self._selectedBackendId].clear() + self._messagesViews[self._selectedBackendId].clear() + self._contactsViews[self._selectedBackendId].clear() + self._change_loggedin_status(self.NULL_BACKEND) + + self._spawn_attempt_login(True) + except Exception, e: + self._errorDisplay.push_exception() def _on_notebook_switch_page(self, notebook, page, pageIndex): - 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() + try: + self._reset_tab_refresh() + + didRecentUpdate = False + didMessagesUpdate = False + + if pageIndex == self.RECENT_TAB: + didRecentUpdate = self._historyViews[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" + def _on_sms_clicked(self, numbers, message): try: - loggedIn = self._phoneBackends[self._selectedBackendId].is_authed() - except StandardError, e: - loggedIn = False - self._errorDisplay.push_exception() - return + assert numbers, "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: - self._errorDisplay.push_exception() + dialed = False + try: + self._phoneBackends[self._selectedBackendId].send_sms(numbers, message) + hildonize.show_information_banner(self._window, "Sending to %s" % ", ".join(numbers)) + _moduleLogger.info("Sending SMS to %r" % numbers) + 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_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: + dialed = False + try: + assert self._phoneBackends[self._selectedBackendId].get_callback_number() != "", "No callback number specified" + self._phoneBackends[self._selectedBackendId].call(number) + hildonize.show_information_banner(self._window, "Calling %s" % number) + _moduleLogger.info("Calling %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() - if dialed: - self._dialpads[self._selectedBackendId].clear() + def _on_contact_import(self, *args): + try: + csvFilter = gtk.FileFilter() + csvFilter.set_name("Contacts") + csvFilter.add_pattern("*.csv") + importFileChooser = gtk.FileChooserDialog( + title="Contacts", + parent=self._window, + ) + importFileChooser.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) + importFileChooser.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) + + importFileChooser.set_property("filter", csvFilter) + userResponse = importFileChooser.run() + importFileChooser.hide() + if userResponse == gtk.RESPONSE_OK: + filename = importFileChooser.get_filename() + shutil.copy2(filename, self._fsContactsPath) + 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("%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/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(): @@ -742,10 +953,11 @@ def run_dialpad(): #with gtk_toolbox.flock(_lock_file, 0): gtk.gdk.threads_init() - if hildonize.IS_HILDON: + if hildonize.IS_HILDON_SUPPORTED: gtk.set_application_name(constants.__pretty_app_name__) handle = Dialcentral() - gtk.main() + if not PROFILE_STARTUP: + gtk.main() class DummyOptions(object): @@ -755,11 +967,7 @@ class DummyOptions(object): if __name__ == "__main__": - if hildonize.IS_HILDON: - userLogPath = "%s/dialcentral.log" % constants._data_path_ - logging.basicConfig(level=logging.DEBUG, filename=userLogPath) - else: - logging.basicConfig(level=logging.DEBUG) + logging.basicConfig(level=logging.DEBUG) try: if len(sys.argv) > 1: try: