Add accounts' dialogue for the new providers, and make gtkui actually
authorAndrew Flegg <andrew@bleb.org>
Sun, 6 Jun 2010 16:06:53 +0000 (17:06 +0100)
committerAndrew Flegg <andrew@bleb.org>
Sun, 6 Jun 2010 16:16:56 +0000 (17:16 +0100)
start, when launched from main.py.

package/src/main.py
package/src/org/bleb/wimpworks.py
package/src/org/maemo/hermes/engine/provider.py
package/src/org/maemo/hermes/gui/accountsdialogue.py [new file with mode: 0644]
package/src/org/maemo/hermes/gui/gtkui.py

index 28484e6..9a50a38 100644 (file)
@@ -1,6 +1,16 @@
 #!/usr/bin/env python
 
-from org.maemo.hermes.gui import HermesGUI
-gui = HermesGUI()
+import org.maemo.hermes.engine.facebook.provider
+import org.maemo.hermes.engine.twitter.provider
+import org.maemo.hermes.engine.gravatar.provider
+import org.maemo.hermes.engine.linkedin.provider
+from org.maemo.hermes.gui.gtkui import HermesGUI
+
+gui = HermesGUI(providers = [
+                 org.maemo.hermes.engine.facebook.provider.Provider(),
+                 org.maemo.hermes.engine.twitter.provider.Provider(),
+                 org.maemo.hermes.engine.gravatar.provider.Provider(),
+                 org.maemo.hermes.engine.linkedin.provider.Provider(),
+             ])
 gui.run()
 
index 4f602f2..08e0d65 100644 (file)
@@ -4,7 +4,7 @@
 #                                       http://www.bleb.org/
 
 import gettext
-import gtk, gobject
+import gtk, gobject, glib
 import re
 import thread
 import os.path
@@ -95,10 +95,13 @@ class WimpWorks:
         file = "/opt/%s/share/%s" % (re.sub('[^a-z0-9_]', '', self.name.lower()), file)
         if not window:
             window = self.main_window
-          
-        self._background, mask = gtk.gdk.pixbuf_new_from_file(file).render_pixmap_and_mask()
-        window.realize()
-        window.window.set_back_pixmap(self._background, False)
+
+        try:
+            self._background, mask = gtk.gdk.pixbuf_new_from_file(file).render_pixmap_and_mask()
+            window.realize()
+            window.window.set_back_pixmap(self._background, False)
+        except glib.GError, e:
+            print "Couldn't find background:", e.message
     
       
     # -----------------------------------------------------------------------
index 01d2daf..5ed4ea5 100644 (file)
@@ -1,3 +1,5 @@
+import re
+
 class Provider:
     """The notional `Provider' which defines the interface which all service
        providers for Hermes must meet. Implementations of this class are expected
@@ -14,6 +16,26 @@ class Provider:
            all-alphabetic version of this name is expected to be provided."""
            
         return None
+
+
+    # -----------------------------------------------------------------------
+    def get_id(self):
+        """Return the ID of this service. This should be alphanumeric characters
+           only. The default implementation is the lowercase version of get_name()
+           with all non-alphanumeric characters removed.
+           
+           Overridding this method is NOT recommended."""
+           
+        return re.sub('[^a-z0-9]+', '', self.get_name().lower())
+
+
+    # -----------------------------------------------------------------------
+    def get_account_detail(self):
+        """Return information on the configured account. This would, typically,
+           be the user's login for the service. If None is returned, no futher
+           information is available."""
+           
+        return None
     
     
     # -----------------------------------------------------------------------
@@ -26,7 +48,10 @@ class Provider:
     
     # -----------------------------------------------------------------------
     def open_preferences(self, parent):
-        """Open the preferences for this provider as a child of the 'parent' widget."""
+        """Open the preferences for this provider as a child of the 'parent' widget.
+           The dialogue box should have a _('Disable') and _('Enable') button; and
+           return True if the user chooses to enable the service; False if not.
+           If the user cancels the dialogue, return None."""
         
         pass
 
diff --git a/package/src/org/maemo/hermes/gui/accountsdialogue.py b/package/src/org/maemo/hermes/gui/accountsdialogue.py
new file mode 100644 (file)
index 0000000..fd52fc3
--- /dev/null
@@ -0,0 +1,114 @@
+import hildon
+import gtk, gobject, glib
+import gettext
+import gnome.gconf
+
+class AccountsDialogue:
+    """Show a dialogue box containing the provided accounts, and their
+       configuration information. Clicking on a provider will open
+       its dialogue box, if any, or toggle enablement if not.
+         
+       Copyright (c) Andrew Flegg <andrew@bleb.org> 2010.
+       Released under the Artistic Licence."""
+
+    # -----------------------------------------------------------------------
+    def __init__(self, window, providers):
+        """Constructor. Passed a parent window, and a list of Providers."""
+
+        self.window    = window
+        self.providers = providers
+        self.gconf     = gnome.gconf.client_get_default()
+
+        self.account_color = self._get_color('ActiveTextColor')
+        self.tick_icon     = gtk.icon_theme_get_default().load_icon('widgets_tickmark_list', 48, 0)
+        self.icons         = {}
+
+        for provider in providers:
+            try:
+                self.icons[provider.get_name()] = gtk.gdk.pixbuf_new_from_file('/opt/hermes/share/account-%s.png' % (provider.get_id()))
+            except glib.GError, e:
+                self.icons[provider.get_name()] = None
+                print "Couldn't find icon:", e.message
+
+
+
+    # -----------------------------------------------------------------------
+    def show(self):
+        """Show the dialogue and handle clicks appropriately."""
+
+        # -- Initialise the Gtk components...
+        #
+        dialog = gtk.Dialog(_('Accounts'), self.window)
+        dialog.add_button(_('Save'), gtk.RESPONSE_OK)
+
+        parea = hildon.PannableArea()
+        store = gtk.ListStore(gtk.gdk.Pixbuf, str, str, gtk.gdk.Pixbuf, gobject.TYPE_PYOBJECT)
+
+        # -- Populate the model...
+        #
+        for provider in self.providers:
+            name = provider.get_name()
+            enabled = self.gconf.get_bool('/apps/maemo/hermes/use_%s' % (provider.get_id()))
+            store.append(row = [self.icons[name],
+                                name,
+                                provider.get_account_detail(),
+                                enabled and self.tick_icon or None,
+                                provider])
+
+        # -- Build the TreeView...
+        #
+        view = gtk.TreeView(store)
+        view.append_column(gtk.TreeViewColumn('Logo', gtk.CellRendererPixbuf(), pixbuf = 0))
+
+        tvcolumn = gtk.TreeViewColumn('Name', gtk.CellRendererText(), text = 1)
+        tvcolumn.set_expand(True)
+        view.append_column(tvcolumn)
+
+        renderer = gtk.CellRendererText()
+        renderer.set_property('foreground-gdk', self.account_color)
+        renderer.set_property('scale', 0.75)
+        tvcolumn = gtk.TreeViewColumn('Account', renderer, text = 2)
+        tvcolumn.set_expand(False)
+        view.append_column(tvcolumn)
+
+        view.append_column(gtk.TreeViewColumn('Enabled', gtk.CellRendererPixbuf(), pixbuf = 3))
+        view.connect('row-activated', self._activated)
+
+        parea.set_size_request_policy(hildon.SIZE_REQUEST_CHILDREN)
+        parea.add(view)
+
+        self.dialog = dialog
+        dialog.vbox.add(parea)
+        dialog.show_all()
+        dialog.run() # We actually always Save. Bad, I know.
+
+
+    # -----------------------------------------------------------------------
+    def _activated(self, treeview, path, column):
+        """A row's been selected. Open its preferences dialogue if any,
+           otherwise just toggle its enabled status."""
+
+        iter      = treeview.get_model().get_iter(path)
+        provider  = treeview.get_model().get_value(iter, 4)
+        use_key   = '/apps/maemo/hermes/use_%s' % (provider.get_id())
+
+        enabled = not self.gconf.get_bool(use_key)
+        if provider.has_preferences():
+            enabled = provider.open_preferences(self.dialog)
+
+        if enabled is not None:
+            self.gconf.set_bool(use_key, enabled)
+            treeview.get_model().set_value(iter, 3, enabled and self.tick_icon or None)
+
+
+    # -----------------------------------------------------------------------
+    def _get_color(self, logicalcolorname):
+        """Return the colour definition for 'logicalcolorname' in the standard
+           styles. This is typically used for getting  'ActiveTextColor', which
+           appears as blue in the default theme on Maemo 5."""
+
+        settings = gtk.settings_get_default()
+        color_style = gtk.rc_get_style_by_paths(settings, 'GtkButton', \
+                                                          'osso-logical-colors', gtk.Button)
+        return color_style.lookup_color(logicalcolorname)
+
index 37524b0..f3fcce3 100644 (file)
@@ -3,11 +3,12 @@ import gtk, gobject
 import traceback
 import time
 import thread
-from org.maemo.hermes.gui.contactview import ContactView
 import urllib2
 import hildon
 from org.bleb.wimpworks import WimpWorks
+from org.maemo.hermes.gui.contactview import ContactView
 from org.maemo.hermes.gui.mapcontact import MapContact
+from org.maemo.hermes.gui.accountsdialogue import AccountsDialogue
 from org.bleb.wimpworks import HildonMainScreenLayout
 #from hermes import Hermes ### FIXME This needs to be new
 
@@ -20,9 +21,9 @@ class HermesGUI(WimpWorks):
 
 
     # -----------------------------------------------------------------------
-    def __init__(self):
+    def __init__(self, providers = None):
         gettext.install('hermes','/opt/hermes/share/locale/')
-        WimpWorks.__init__(self, 'Hermes', version = '0.2.0', dbus_name = 'org.maemo.hermes')
+        WimpWorks.__init__(self, 'Hermes', version = '0.9.0', dbus_name = 'org.maemo.hermes')
         self.set_background('background.png')
         
         layout = HildonMainScreenLayout(offset = 0.8, container = self)
@@ -31,6 +32,9 @@ class HermesGUI(WimpWorks):
         
         self.add_menu_action("Accounts")
         self.menu.show_all()
+        
+        self.providers = providers
+        self.progressnote = None
 
   
     # -----------------------------------------------------------------------
@@ -45,49 +49,18 @@ class HermesGUI(WimpWorks):
 
     # -----------------------------------------------------------------------
     def do_accounts(self, widget = None):
-        dialog = gtk.Dialog(_('Accounts'), self.main_window)
-        dialog.add_button(_('Save'), gtk.RESPONSE_OK)
-        
-        #pa = hildon.PannableArea()
-        #dialog.vbox.add(pa)
-        content = dialog.vbox 
-        #content = gtk.VBox()
-        #pa.add(content)
-        #pa.set_size_request(600, 380)
-        
-        use_facebook = self.new_checkbox(_('Use Facebook'), content)
-        use_facebook.set_active(self.get_use_facebook())
-        
-        indent = self.new_indent(content)
-        self.link_control(use_facebook, gtk.Label(_('Note: authentication via web page')), indent)
-        
-        fb_empty = self.link_control(use_facebook, self.new_checkbox(_('Create birthday-only contacts')), indent)
-        fb_empty.set_active(self.get_create_empty())
-        
-        use_twitter = self.new_checkbox(_('Use Twitter'), content)
-        use_twitter.set_active(self.get_use_twitter())
-        
-        indent = self.new_indent(content)
-        tw_user = self.link_control(use_twitter, self.new_input(_('Twitter username')), indent)
-        tw_user.set_text(self.get_twitter_credentials()[0])
-        
-        tw_pass = self.link_control(use_twitter, self.new_input(_('Twitter password'), password = True), indent)
-        tw_pass.set_text(self.get_twitter_credentials()[1])
-        
-        dialog.show_all()
-        result = dialog.run()
-        dialog.hide()
-        if result == gtk.RESPONSE_OK:
-            self.set_use_facebook(use_facebook.get_active())
-            self.set_create_empty(fb_empty.get_active())
-            self.set_use_twitter(use_twitter.get_active(), tw_user.get_text(), tw_pass.get_text())
-        
-        return result
+        dialog = AccountsDialogue(self.main_window, self.providers)
+        dialog.show()
    
 
     # -----------------------------------------------------------------------
     def sync(self, widget, force, main = True):
-        if main and not self.get_use_facebook() and not self.get_use_twitter():
+        enabled = []
+        for provider in self.providers:
+            if self.gconf.get_bool('/apps/maemo/hermes/use_%s' % (provider.get_id())):
+                enabled.append(provider)
+                
+        if main and len(enabled) == 0:
             saved = self.do_accounts()
             if saved == gtk.RESPONSE_DELETE_EVENT:
                 return
@@ -97,13 +70,7 @@ class HermesGUI(WimpWorks):
             thread.start_new_thread(self.sync, (widget, force, False))
         else:
             try:
-                fb2c = Hermes(self,
-                              twitter = (self.get_use_twitter() and self.get_twitter_credentials()) or None,
-                              facebook = self.get_use_facebook(),
-                              empty = self.get_create_empty())
-                fb2c.load_friends()
-                fb2c.sync_contacts(resync = force)
-                gobject.idle_add(self.open_summary, fb2c)
+                raise Exception("TODO - implement syncing")
         
             except urllib2.HTTPError, e:
                 traceback.print_exc()
@@ -186,37 +153,8 @@ class HermesGUI(WimpWorks):
                 else:
                     if fb2c.update_contact(contact, friend, False):
                         fb2c.addresses.commit_contact(contact)
-    
-      
-    # -----------------------------------------------------------------------
-    def need_auth(self, main = False):
-        if main:
-            hildon.hildon_banner_show_information(self.main_window, '', _("Need to authenticate with Facebook"))
-        else:
-            gobject.idle_add(self.need_auth, True)
-      
-    
-    # -----------------------------------------------------------------------
-    def block_for_auth(self, main = False, lock = None):
-        if main:
-            note = gtk.Dialog(_('Facebook authorisation'), self.main_window)
-            note.add_button(_("Validate"), gtk.RESPONSE_OK)
-            note.vbox.add(gtk.Label(_("\nPress 'Validate' once Facebook has\nbeen authenticated in web browser.\n")))
-    
-            note.show_all()
-            result = note.run()
-            note.hide()
-            lock.release()
-        
-        else:
-            time.sleep(2)
-            lock = thread.allocate_lock()
-            lock.acquire()
-            gobject.idle_add(self.block_for_auth, True, lock)
-            lock.acquire()
-            lock.release()
-    
-    
+                        
+                        
     # -----------------------------------------------------------------------
     def progress(self, i, j, main = False):
         if main:
@@ -241,8 +179,8 @@ class HermesGUI(WimpWorks):
             print i,j
         else:
             gobject.idle_add(self.progress, i, j, True)
-    
-    
+
+       
     # -----------------------------------------------------------------------
     def report_error(self, e, prefs = False):
         if self.progressnote:
@@ -252,33 +190,3 @@ class HermesGUI(WimpWorks):
         hildon.hildon_banner_show_information(self.main_window, '', e)
         if prefs:
             self.do_accounts()
-    
-        
-    def get_use_facebook(self):
-        return self.gconf.get_bool("/apps/maemo/hermes/use_facebook")
-    
-    
-    def set_use_facebook(self, value):
-        self.gconf.set_bool("/apps/maemo/hermes/use_facebook", value)
-    
-    def get_create_empty(self):
-        return self.gconf.get_bool("/apps/maemo/hermes/create_empty")
-    
-    
-    def set_create_empty(self, value):
-        self.gconf.set_bool("/apps/maemo/hermes/create_empty", value)
-    
-    
-    def get_use_twitter(self):
-        return self.gconf.get_bool("/apps/maemo/hermes/use_twitter")
-    
-    
-    def set_use_twitter(self, value, user, password):
-        self.gconf.set_bool("/apps/maemo/hermes/use_twitter", value)
-        self.gconf.set_string("/apps/maemo/hermes/twitter_user", user)
-        self.gconf.set_string("/apps/maemo/hermes/twitter_pwd", password)
-      
-    
-    def get_twitter_credentials(self):
-        return (self.gconf.get_string("/apps/maemo/hermes/twitter_user") or '',
-                self.gconf.get_string("/apps/maemo/hermes/twitter_pwd") or '')