X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=src%2Fdc_glade.py;h=6923606d57f60d5ee04f53c9a4a2c38532d5bf96;hb=64e977c1831d5053321546c2f2a613cba29d0bc1;hp=2a3d7c97b1efa28f64b9b18cd26b754766b16a5d;hpb=641e0ea7cb953903458929e54ad09373f5e028f2;p=gc-dialer diff --git a/src/dc_glade.py b/src/dc_glade.py index 2a3d7c9..6923606 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 @@ -39,6 +39,10 @@ import hildonize import gtk_toolbox +_moduleLogger = logging.getLogger("dc_glade") +PROFILE_STARTUP = False + + def getmtime_nothrow(path): try: return os.path.getmtime(path) @@ -70,6 +74,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) @@ -111,56 +116,76 @@ 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 ( + for scrollingWidgetName in ( 'recent_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)) - - hildonize.hildonize_menu(self._window, self._widgetTree.get_widget("dialpad_menubar")) - - 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") + 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) + + replacementButtons = [gtk.Button("Test")] + menu = hildonize.hildonize_menu( + self._window, + self._widgetTree.get_widget("dialpad_menubar"), + replacementButtons + ) + 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") hildonize.set_application_title(self._window, "%s" % constants.__pretty_app_name__) - callbackMapping = { - "on_dialpad_quit": self._on_close, - } - self._widgetTree.signal_autoconnect(callbackMapping) - self._window.connect("destroy", self._on_close) self._window.set_default_size(800, 300) self._window.show_all() 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 import null_views @@ -177,8 +202,12 @@ 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, OSError): @@ -189,23 +218,32 @@ class Dialcentral(object): device = osso.DeviceState(self._osso) device.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() + 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, OSError): @@ -216,9 +254,13 @@ 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 + # Setup costly backends + try: import gv_backend import file_backend import gv_views @@ -281,10 +323,12 @@ 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, } - 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 = [ @@ -304,44 +348,50 @@ 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() - 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 Exception, e: - logging.exception('Session refresh failed with the following message "%s"' % e.message) + _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) + 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 @@ -363,7 +413,7 @@ class Dialcentral(object): """ 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]) return loggedIn def _login_by_settings(self): @@ -374,40 +424,46 @@ class Dialcentral(object): 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) + 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 - 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): 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": self._on_dial_clicked(number) elif action == "sms": self._on_sms_clicked(number, message) @@ -433,16 +489,21 @@ 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")) + 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)) @@ -456,14 +517,14 @@ class Dialcentral(object): if self._alarmHandler is not None: self._alarmHandler.load_settings(config, "alarm") 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, @@ -481,26 +542,55 @@ class Dialcentral(object): 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()))) for i, value in enumerate(self._credentials): blob = base64.b64encode(value) config.set(constants.__pretty_app_name__, "bin_blob_%i" % i, blob) @@ -584,7 +674,7 @@ class Dialcentral(object): if status == conic.STATUS_CONNECTED: if self._initDone: - self._spawn_attempt_login(2) + self._spawn_attempt_login() elif status == conic.STATUS_DISCONNECTED: if self._initDone: self._defaultBackendId = self._selectedBackendId @@ -608,8 +698,12 @@ class Dialcentral(object): """ @note Hildon specific """ + RETURN_TYPES = (gtk.keysyms.Return, gtk.keysyms.ISO_Enter, gtk.keysyms.KP_Enter) try: - if event.keyval == gtk.keysyms.F6: + 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: @@ -626,7 +720,7 @@ class Dialcentral(object): self._contactsViews[self._selectedBackendId].clear() self._change_loggedin_status(self.NULL_BACKEND) - self._spawn_attempt_login(2, True) + self._spawn_attempt_login(True) except Exception, e: self._errorDisplay.push_exception() @@ -691,13 +785,14 @@ class Dialcentral(object): if not loggedIn: self._errorDisplay.push_message( - "Backend link with grandcentral is not working, please try again" + "Backend link with GoogleVoice is not working, please try again" ) return 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() @@ -719,7 +814,7 @@ class Dialcentral(object): if not loggedIn: self._errorDisplay.push_message( - "Backend link with grandcentral is not working, please try again" + "Backend link with GoogleVoice is not working, please try again" ) return @@ -727,6 +822,7 @@ class Dialcentral(object): 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() @@ -745,7 +841,8 @@ class Dialcentral(object): def _on_paste(self, *args): try: contents = self._clipboard.wait_for_text() - self._dialpads[self._selectedBackendId].set_number(contents) + if contents is not None: + self._dialpads[self._selectedBackendId].set_number(contents) except Exception, e: self._errorDisplay.push_exception() @@ -755,7 +852,7 @@ class Dialcentral(object): 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_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() @@ -780,10 +877,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):