start, when launched from main.py.
#!/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()
# http://www.bleb.org/
import gettext
-import gtk, gobject
+import gtk, gobject, glib
import re
import thread
import os.path
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
# -----------------------------------------------------------------------
+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
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
# -----------------------------------------------------------------------
# -----------------------------------------------------------------------
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
--- /dev/null
+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)
+
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
# -----------------------------------------------------------------------
- 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)
self.add_menu_action("Accounts")
self.menu.show_all()
+
+ self.providers = providers
+ self.progressnote = None
# -----------------------------------------------------------------------
# -----------------------------------------------------------------------
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
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()
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:
print i,j
else:
gobject.idle_add(self.progress, i, j, True)
-
-
+
+
# -----------------------------------------------------------------------
def report_error(self, e, prefs = False):
if self.progressnote:
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 '')