The start of a settings file and removed the timeouts on the different view refreshes
authorepage <eopage@byu.net>
Sat, 23 May 2009 00:26:39 +0000 (00:26 +0000)
committerepage <eopage@byu.net>
Sat, 23 May 2009 00:26:39 +0000 (00:26 +0000)
git-svn-id: file:///svnroot/gc-dialer/trunk@311 c39d3808-3fe2-4d86-a59f-b7f623ee9f21

src/dc_glade.py
src/gc_views.py
src/gtk_toolbox.py
src/null_views.py

index 0d49fd1..3f8d50f 100755 (executable)
@@ -18,6 +18,8 @@ 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
 
+@bug Completely broken on Maemo
+@todo Add storing of credentials like DoneIt
 @todo Add logging support to make debugging issues for people a lot easier
 """
 
@@ -28,6 +30,9 @@ import sys
 import gc
 import os
 import threading
+import base64
+import ConfigParser
+import itertools
 import warnings
 import traceback
 
@@ -49,6 +54,15 @@ def getmtime_nothrow(path):
                return 0
 
 
+def display_error_message(msg):
+       error_dialog = gtk.MessageDialog(None, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, msg)
+
+       def close(dialog, response):
+               dialog.destroy()
+       error_dialog.connect("response", close)
+       error_dialog.run()
+
+
 class Dialcentral(object):
 
        __pretty_app_name__ = "DialCentral"
@@ -74,13 +88,16 @@ class Dialcentral(object):
        BACKENDS = (NULL_BACKEND, GC_BACKEND, GV_BACKEND)
 
        _data_path = os.path.join(os.path.expanduser("~"), ".dialcentral")
+       _user_settings = "%s/settings.ini" % _data_path
 
        def __init__(self):
+               self._initDone = False
                self._connection = None
                self._osso = None
                self._clipboard = gtk.clipboard_get()
 
                self._deviceIsOnline = True
+               self._credentials = ("", "")
                self._selectedBackendId = self.NULL_BACKEND
                self._defaultBackendId = self.GC_BACKEND
                self._phoneBackends = None
@@ -95,14 +112,14 @@ class Dialcentral(object):
                                self._widgetTree = gtk.glade.XML(path)
                                break
                else:
-                       self.display_error_message("Cannot find dialcentral.glade")
+                       display_error_message("Cannot find dialcentral.glade")
                        gtk.main_quit()
                        return
 
                self._window = self._widgetTree.get_widget("mainWindow")
                self._notebook = self._widgetTree.get_widget("notebook")
                self._errorDisplay = gtk_toolbox.ErrorDisplay(self._widgetTree)
-               self._credentials = gtk_toolbox.LoginWindow(self._widgetTree)
+               self._credentialsDialog = gtk_toolbox.LoginWindow(self._widgetTree)
 
                self._app = None
                self._isFullScreen = False
@@ -140,7 +157,7 @@ class Dialcentral(object):
                self._widgetTree.signal_autoconnect(callbackMapping)
 
                if self._window:
-                       self._window.connect("destroy", gtk.main_quit)
+                       self._window.connect("destroy", self._on_close)
                        self._window.show_all()
                        self._window.set_default_size(800, 300)
 
@@ -283,6 +300,13 @@ class Dialcentral(object):
                }
                self._widgetTree.signal_autoconnect(callbackMapping)
 
+               self._initDone = True
+
+               config = ConfigParser.SafeConfigParser()
+               config.read(self._user_settings)
+               with gtk_toolbox.gtk_lock():
+                       self.load_settings(config)
+
                self.attempt_login(2)
 
                return False
@@ -309,6 +333,7 @@ class Dialcentral(object):
                        if self._phoneBackends[self._defaultBackendId].is_authed():
                                serviceId = self._defaultBackendId
                                loggedIn = True
+                               username, password = self._credentials
                        for x in xrange(numOfAttempts):
                                if loggedIn:
                                        break
@@ -317,7 +342,9 @@ class Dialcentral(object):
                                                self.GV_BACKEND: "Google Voice",
                                                self.GC_BACKEND: "Grand Central",
                                        }
-                                       credentials = self._credentials.request_credentials_from(availableServices)
+                                       credentials = self._credentialsDialog.request_credentials_from(
+                                               availableServices, defaultCredentials = self._credentials
+                                       )
                                        serviceId, username, password = credentials
 
                                loggedIn = self._phoneBackends[serviceId].login(username, password)
@@ -326,24 +353,22 @@ class Dialcentral(object):
                        self._errorDisplay.push_exception_with_lock(e)
 
                with gtk_toolbox.gtk_lock():
-                       if not loggedIn:
+                       if loggedIn:
+                               self._credentials = username, password
+                       else:
                                self._errorDisplay.push_message("Login Failed")
                        self._change_loggedin_status(serviceId if loggedIn else self.NULL_BACKEND)
                return loggedIn
 
-       def display_error_message(self, msg):
-               error_dialog = gtk.MessageDialog(None, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, msg)
-
-               def close(dialog, response, editor):
-                       editor.about_dialog = None
-                       dialog.destroy()
-               error_dialog.connect("response", close, self)
-               error_dialog.run()
-
        def _on_close(self, *args, **kwds):
-               if self._osso is not None:
-                       self._osso.close()
-               gtk.main_quit()
+               try:
+                       if self._osso is not None:
+                               self._osso.close()
+
+                       if self._initDone:
+                               self._save_settings()
+               finally:
+                       gtk.main_quit()
 
        def _change_loggedin_status(self, newStatus):
                oldStatus = self._selectedBackendId
@@ -368,6 +393,50 @@ class Dialcentral(object):
 
                self._selectedBackendId = newStatus
 
+       def load_settings(self, config):
+               """
+               @note UI Thread
+               """
+               self._defaultBackendId = int(config.get(self.__pretty_app_name__, "active"))
+               blobs = (
+                       config.get(self.__pretty_app_name__, "bin_blob_%i" % i)
+                       for i in xrange(len(self._credentials))
+               )
+               creds = (
+                       base64.b64decode(blob)
+                       for blob in blobs
+               )
+               self._credentials = tuple(creds)
+               for backendId, view in itertools.chain(
+                       self._dialpads.iteritems(),
+                       self._accountViews.iteritems(),
+                       self._messagesViews.iteritems(),
+                       self._recentViews.iteritems(),
+                       self._contactsViews.iteritems(),
+               ):
+                       sectionName = "%s - %s" % (backendId, view.name())
+                       view.load_settings(config, sectionName)
+
+       def save_settings(self, config):
+               """
+               @note Thread Agnostic
+               """
+               config.add_section(self.__pretty_app_name__)
+               config.set(self.__pretty_app_name__, "active", str(self._selectedBackendId))
+               for i, value in enumerate(self._credentials):
+                       blob = base64.b64encode(value)
+                       config.set(self.__pretty_app_name__, "bin_blob_%i" % i, blob)
+               for backendId, view in itertools.chain(
+                       self._dialpads.iteritems(),
+                       self._accountViews.iteritems(),
+                       self._messagesViews.iteritems(),
+                       self._recentViews.iteritems(),
+                       self._contactsViews.iteritems(),
+               ):
+                       sectionName = "%s - %s" % (backendId, view.name())
+                       config.add_section(sectionName)
+                       view.save_settings(config, sectionName)
+
        def _guess_preferred_backend(self, backendAndCookiePaths):
                modTimeAndPath = [
                        (getmtime_nothrow(path), backendId, path)
@@ -376,6 +445,15 @@ class Dialcentral(object):
                modTimeAndPath.sort()
                return modTimeAndPath[-1][1]
 
+       def _save_settings(self):
+               """
+               @note Thread Agnostic
+               """
+               config = ConfigParser.SafeConfigParser()
+               self.save_settings(config)
+               with open(self._user_settings, "wb") as configFile:
+                       config.write(configFile)
+
        def _on_device_state_change(self, shutdown, save_unsaved_data, memory_low, system_inactivity, message, userData):
                """
                For shutdown or save_unsaved_data, our only state is cookies and I think the cookie manager handles that for us.
@@ -389,6 +467,9 @@ class Dialcentral(object):
                        self._contactsViews[self._selectedBackendId].clear_caches()
                        gc.collect()
 
+               if save_unsaved_data or shutdown:
+                       self._save_settings()
+
        def _on_connection_change(self, connection, event, magicIdentifier):
                """
                @note Hildon specific
index 96be9bd..41420ef 100644 (file)
@@ -22,7 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 from __future__ import with_statement
 
 import threading
-import time
 import warnings
 
 import gobject
@@ -531,6 +530,19 @@ class Dialpad(object):
        def clear(self):
                self.set_number("")
 
+       @staticmethod
+       def name():
+               return "Dialpad"
+
+       def load_settings(self, config, section):
+               pass
+
+       def save_settings(self, config, section):
+               """
+               @note Thread Agnostic
+               """
+               pass
+
        def _on_dial_clicked(self, widget):
                self.dial(self.get_number())
 
@@ -567,6 +579,8 @@ class AccountInfo(object):
                self._callbackCombo = widgetTree.get_widget("callbackcombo")
                self._onCallbackentryChangedId = 0
 
+               self._defaultCallback = ""
+
        def enable(self):
                assert self._backend.is_authed()
                self._accountViewNumberDisplay.set_use_markup(True)
@@ -590,14 +604,28 @@ class AccountInfo(object):
                self._accountViewNumberDisplay.set_label("<span size='23000' weight='bold'>%s</span>" % (number))
 
        def update(self, force = False):
-               self.populate_callback_combo()
+               self._populate_callback_combo()
                self.set_account_number(self._backend.get_account_number())
 
        def clear(self):
                self._callbackCombo.get_child().set_text("")
                self.set_account_number("")
 
-       def populate_callback_combo(self):
+       @staticmethod
+       def name():
+               return "Account Info"
+
+       def load_settings(self, config, section):
+               self._defaultCallback = config.get(section, "callback")
+
+       def save_settings(self, config, section):
+               """
+               @note Thread Agnostic
+               """
+               callback = self.get_selected_callback_number()
+               config.set(section, "callback", callback)
+
+       def _populate_callback_combo(self):
                self._callbackList.clear()
                try:
                        callbackNumbers = self._backend.get_callback_numbers()
@@ -613,8 +641,7 @@ class AccountInfo(object):
                try:
                        callbackNumber = self._backend.get_callback_number()
                except RuntimeError, e:
-                       self._errorDisplay.push_exception(e)
-                       return
+                       callbackNumber = self._defaultCallback
                self._callbackCombo.get_child().set_text(make_pretty(callbackNumber))
 
        def _on_callbackentry_changed(self, *args):
@@ -639,7 +666,7 @@ class RecentCallsView(object):
                self._errorDisplay = errorDisplay
                self._backend = backend
 
-               self._recenttime = 0.0
+               self._isPopulated = False
                self._recentmodel = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
                self._recentview = widgetTree.get_widget("recentview")
                self._recentviewselection = None
@@ -676,25 +703,38 @@ class RecentCallsView(object):
                raise NotImplementedError
 
        def update(self, force = False):
-               if not force and (time.time() - self._recenttime) < 300:
+               if not force and self._isPopulated:
                        return
                backgroundPopulate = threading.Thread(target=self._idly_populate_recentview)
                backgroundPopulate.setDaemon(True)
                backgroundPopulate.start()
 
        def clear(self):
-               self._recenttime = 0.0
+               self._isPopulated = False
                self._recentmodel.clear()
 
+       @staticmethod
+       def name():
+               return "Recent Calls"
+
+       def load_settings(self, config, section):
+               pass
+
+       def save_settings(self, config, section):
+               """
+               @note Thread Agnostic
+               """
+               pass
+
        def _idly_populate_recentview(self):
-               self._recenttime = time.time()
+               self._isPopulated = True
                self._recentmodel.clear()
 
                try:
                        recentItems = self._backend.get_recent()
                except RuntimeError, e:
                        self._errorDisplay.push_exception_with_lock(e)
-                       self._recenttime = 0.0
+                       self._isPopulated = False
                        recentItems = []
 
                for personsName, phoneNumber, date, action in recentItems:
@@ -730,7 +770,7 @@ class MessagesView(object):
                self._errorDisplay = errorDisplay
                self._backend = backend
 
-               self._messagetime = 0.0
+               self._isPopulated = False
                self._messagemodel = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
                self._messageview = widgetTree.get_widget("messages_view")
                self._messageviewselection = None
@@ -767,25 +807,38 @@ class MessagesView(object):
                raise NotImplementedError
 
        def update(self, force = False):
-               if not force and (time.time() - self._messagetime) < 300:
+               if not force and self._isPopulated:
                        return
                backgroundPopulate = threading.Thread(target=self._idly_populate_messageview)
                backgroundPopulate.setDaemon(True)
                backgroundPopulate.start()
 
        def clear(self):
-               self._messagetime = 0.0
+               self._isPopulated = False
                self._messagemodel.clear()
 
+       @staticmethod
+       def name():
+               return "Messages"
+
+       def load_settings(self, config, section):
+               pass
+
+       def save_settings(self, config, section):
+               """
+               @note Thread Agnostic
+               """
+               pass
+
        def _idly_populate_messageview(self):
-               self._messagetime = time.time()
+               self._isPopulated = True
                self._messagemodel.clear()
 
                try:
                        messageItems = self._backend.get_messages()
                except RuntimeError, e:
                        self._errorDisplay.push_exception_with_lock(e)
-                       self._messagetime = 0.0
+                       self._isPopulated = False
                        messageItems = []
 
                for header, number, relativeDate, message in messageItems:
@@ -825,7 +878,7 @@ class ContactsView(object):
                self._booksList = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
                self._booksSelectionBox = widgetTree.get_widget("addressbook_combo")
 
-               self._contactstime = 0.0
+               self._isPopulated = False
                self._contactsmodel = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
                self._contactsviewselection = None
                self._contactsview = widgetTree.get_widget("contactsview")
@@ -905,20 +958,17 @@ class ContactsView(object):
 
        def open_addressbook(self, bookFactoryId, bookId):
                self._addressBook = self._addressBookFactories[bookFactoryId].open_addressbook(bookId)
-               self._contactstime = 0
-               backgroundPopulate = threading.Thread(target=self._idly_populate_contactsview)
-               backgroundPopulate.setDaemon(True)
-               backgroundPopulate.start()
+               self.update(force=True)
 
        def update(self, force = False):
-               if not force and (time.time() - self._contactstime) < 300:
+               if not force and self._isPopulated:
                        return
                backgroundPopulate = threading.Thread(target=self._idly_populate_contactsview)
                backgroundPopulate.setDaemon(True)
                backgroundPopulate.start()
 
        def clear(self):
-               self._contactstime = 0.0
+               self._isPopulated = False
                self._contactsmodel.clear()
 
        def clear_caches(self):
@@ -932,8 +982,21 @@ class ContactsView(object):
        def extend(self, books):
                self._addressBookFactories.extend(books)
 
+       @staticmethod
+       def name():
+               return "Contacts"
+
+       def load_settings(self, config, section):
+               pass
+
+       def save_settings(self, config, section):
+               """
+               @note Thread Agnostic
+               """
+               pass
+
        def _idly_populate_contactsview(self):
-               #@todo Add a lock so only one code path can be in here at a time
+               self._isPopulated = True
                self.clear()
 
                # completely disable updating the treeview while we populate the data
@@ -945,7 +1008,7 @@ class ContactsView(object):
                        contacts = addressBook.get_contacts()
                except RuntimeError, e:
                        contacts = []
-                       self._contactstime = 0.0
+                       self._isPopulated = False
                        self._errorDisplay.push_exception_with_lock(e)
                for contactId, contactName in contacts:
                        contactType = (addressBook.contact_source_short_name(contactId), )
@@ -975,7 +1038,6 @@ class ContactsView(object):
                        contactDetails = self._addressBook.get_contact_details(contactId)
                except RuntimeError, e:
                        contactDetails = []
-                       self._contactstime = 0.0
                        self._errorDisplay.push_exception(e)
                contactPhoneNumbers = [phoneNumber for phoneNumber in contactDetails]
 
index 9559b45..2a04efd 100644 (file)
@@ -122,7 +122,11 @@ class LoginWindow(object):
 
                return username, password
 
-       def request_credentials_from(self, services, parentWindow = None):
+       def request_credentials_from(self,
+               services,
+               parentWindow = None,
+               defaultCredentials = ("", "")
+       ):
                """
                @note UI Thread
                """
@@ -135,6 +139,9 @@ class LoginWindow(object):
                self._serviceCombo.set_active(0)
                self._serviceCombo.show()
 
+               self._usernameEntry.set_text(defaultCredentials[0])
+               self._passwordEntry.set_text(defaultCredentials[1])
+
                try:
                        self._dialog.set_transient_for(parentWindow)
                        self._dialog.set_default_response(gtk.RESPONSE_OK)
@@ -144,7 +151,6 @@ class LoginWindow(object):
 
                        username = self._usernameEntry.get_text()
                        password = self._passwordEntry.get_text()
-                       self._passwordEntry.set_text("")
                finally:
                        self._dialog.hide()
 
index 35f5c6b..034eeb6 100644 (file)
@@ -35,6 +35,19 @@ class Dialpad(object):
        def disable(self):
                self._dialButton.set_sensitive(True)
 
+       @staticmethod
+       def name():
+               return "Dialpad"
+
+       def load_settings(self, config, sectionName):
+               pass
+
+       def save_settings(self, config, sectionName):
+               """
+               @note Thread Agnostic
+               """
+               pass
+
 
 class AccountInfo(object):
 
@@ -62,6 +75,19 @@ class AccountInfo(object):
        def clear():
                pass
 
+       @staticmethod
+       def name():
+               return "Account Info"
+
+       def load_settings(self, config, sectionName):
+               pass
+
+       def save_settings(self, config, sectionName):
+               """
+               @note Thread Agnostic
+               """
+               pass
+
 
 class RecentCallsView(object):
 
@@ -81,6 +107,19 @@ class RecentCallsView(object):
        def clear():
                pass
 
+       @staticmethod
+       def name():
+               return "Recent Calls"
+
+       def load_settings(self, config, sectionName):
+               pass
+
+       def save_settings(self, config, sectionName):
+               """
+               @note Thread Agnostic
+               """
+               pass
+
 
 class MessagesView(object):
 
@@ -100,6 +139,19 @@ class MessagesView(object):
        def clear():
                pass
 
+       @staticmethod
+       def name():
+               return "Messages"
+
+       def load_settings(self, config, sectionName):
+               pass
+
+       def save_settings(self, config, sectionName):
+               """
+               @note Thread Agnostic
+               """
+               pass
+
 
 class ContactsView(object):
 
@@ -118,3 +170,16 @@ class ContactsView(object):
        @staticmethod
        def clear():
                pass
+
+       @staticmethod
+       def name():
+               return "Contacts"
+
+       def load_settings(self, config, sectionName):
+               pass
+
+       def save_settings(self, config, sectionName):
+               """
+               @note Thread Agnostic
+               """
+               pass