10 from org.bleb.wimpworks import WimpWorks
11 from org.maemo.hermes.gui.contactview import ContactView
12 from org.maemo.hermes.gui.mapcontact import MapContact
13 from org.maemo.hermes.gui.accountsdialogue import AccountsDialogue
14 from org.bleb.wimpworks import HildonMainScreenLayout
15 from org.maemo.hermes.engine.hermes import Hermes
16 from org.maemo.hermes.engine.service import CredentialsExpiredException
18 class HermesGUI(WimpWorks):
19 """Provides the GUI for Hermes, allowing the syncing of Facebook and
20 Twitter friends' information with the Evolution contacts' database.
22 Copyright (c) Andrew Flegg <andrew@bleb.org> 2009.
23 Released under the Artistic Licence."""
26 # -----------------------------------------------------------------------
27 def __init__(self, providers = None):
28 gettext.install('hermes','/opt/hermes/share/locale/')
29 WimpWorks.__init__(self, 'Hermes', version = '0.8.7', dbus_name = 'org.maemo.hermes')
30 self.set_background('background.png')
32 layout = HildonMainScreenLayout(offset = 0.8, container = self)
33 layout.add_button('Retrieve', _("Get contacts' missing info"))
34 layout.add_button('Refresh', _("Update contacts' info"))
36 self.add_menu_action("Accounts")
37 self.add_menu_action("About")
40 self.providers = providers
41 self.progressnote = None
42 connection = conic.Connection()
43 gobject.timeout_add(100, connection.request_connection, conic.CONNECT_FLAG_NONE)
46 # -----------------------------------------------------------------------
47 def do_retrieve(self, widget):
48 self.sync(widget, False)
51 # -----------------------------------------------------------------------
52 def do_refresh(self, widget):
53 self.sync(widget, True)
56 # -----------------------------------------------------------------------
57 def do_accounts(self, widget = None):
58 dialog = AccountsDialogue(self.main_window, self.providers)
62 # -----------------------------------------------------------------------
63 def do_about(self, widget):
64 """Inspired by HeAboutDialog Python port:
65 http://wiki.maemo.org/Hildon-Extras#HeAboutDialog"""
67 dlg = gtk.Dialog(_("About"), self.main_window)
70 icon.set_from_icon_name(self.name.lower(), gtk.ICON_SIZE_DIALOG)
71 icon.set_padding(5, 5)
73 name = gtk.Label(self.name)
74 name.set_alignment(0, 1)
75 hildon.hildon_helper_set_logical_font(name, 'X-LargeSystemFont')
77 version = gtk.Label('v%s' % (self.version))
78 version.set_alignment(0, 1)
79 version.set_padding(10, 0)
80 hildon.hildon_helper_set_logical_font(version, 'LargeSystemFont')
82 desc = gtk.Label(_("Enrich contacts' from social networks."))
83 desc.set_alignment(0, 0)
85 copy = gtk.Label("Copyright (c) 2010 Andrew Flegg, Fredrik Wendt, Tim Samoff")
86 copy.set_alignment(0, 1)
87 copy.set_padding(0, 5)
88 hildon.hildon_helper_set_logical_font(copy, 'SmallSystemFont')
89 hildon.hildon_helper_set_logical_color(copy, gtk.RC_FG, gtk.STATE_NORMAL, "SecondaryTextColor")
91 layout = gtk.Table(3, 3, False)
92 layout.attach(icon, 0, 1, 0, 2, 0, gtk.EXPAND, 0, 0)
93 layout.attach(name, 1, 2, 0, 1, 0, gtk.EXPAND | gtk.FILL, 0, 0)
94 layout.attach(version, 2, 3, 0, 1, gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL, 0, 0)
95 layout.attach(desc, 1, 3, 1, 2, gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL, 0, 0)
96 layout.attach(copy, 0, 3, 2, 3, gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL, 0, 0)
99 dlg.add_button(_('Visit website'), gtk.RESPONSE_APPLY)
100 dlg.add_button(_('Report bug'), gtk.RESPONSE_NO)
103 if response == gtk.RESPONSE_APPLY:
104 webbrowser.open('http://hermes.garage.maemo.org/')
105 elif response == gtk.RESPONSE_NO:
106 webbrowser.open('https://bugs.maemo.org/enter_bug.cgi?product=Hermes')
110 # -----------------------------------------------------------------------
111 def sync(self, widget, force, main = True):
113 for provider in self.providers:
114 if self.gconf.get_bool('/apps/maemo/hermes/use_%s' % (provider.get_id())):
115 enabled.append(provider)
117 if main and len(enabled) == 0:
118 saved = self.do_accounts()
119 if saved == gtk.RESPONSE_DELETE_EVENT:
122 print "doing sync", main
125 self.main_window.set_property('sensitive', False)
126 thread.start_new_thread(self.sync, (widget, force, False))
129 self.progress('', 0, 0)
131 for provider in enabled:
132 services.append(provider.service(self))
134 hermes = Hermes(services, self.progress)
136 gobject.idle_add(self.open_summary, hermes)
138 except urllib2.HTTPError, e:
139 traceback.print_exc()
141 gobject.idle_add(self.report_error, _('Authentication problem. Check credentials.'), True)
143 gobject.idle_add(self.report_error, _('Network connection error. Check connectivity.'))
145 except urllib2.URLError, e:
146 traceback.print_exc()
147 gobject.idle_add(self.report_error, _('Network connection error. Check connectivity.'))
149 except CredentialsExpiredException, e:
150 gobject.idle_add(self.report_error, _('Credentials expired. Please reauthorise %s.') % (e.message))
153 traceback.print_exc()
154 gobject.idle_add(self.report_error, _('Something went wrong: ') + e.message)
157 # -----------------------------------------------------------------------
158 def open_summary(self, fb2c):
159 gobject.idle_add(self.main_window.set_property, 'sensitive', True)
161 dialog = gtk.Dialog(_('Summary'), self.main_window)
162 dialog.add_button(_('Done'), gtk.RESPONSE_OK)
164 button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL,
165 title = _('Updated %d contacts') % (len(fb2c.updated)))
166 button.connect('clicked', self.show_contacts, fb2c, fb2c.updated)
167 button.set_property('sensitive', len(fb2c.updated) > 0)
168 dialog.vbox.add(button)
170 button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL,
171 title = _('Matched %d contacts') % (len(fb2c.matched)))
172 button.connect('clicked', self.show_contacts, fb2c, fb2c.matched)
173 button.set_property('sensitive', len(fb2c.matched) > 0)
174 dialog.vbox.add(button)
176 button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL,
177 title = _('%d contacts unmatched') % (len(fb2c.unmatched)))
178 button.connect('clicked', self.show_contacts, fb2c, fb2c.unmatched)
179 button.set_property('sensitive', len(fb2c.unmatched) > 0)
180 dialog.vbox.add(button)
187 # -----------------------------------------------------------------------
188 def show_contacts(self, widget, fb2c, contacts):
189 view = ContactView(contacts)
191 dialog = gtk.Dialog(_('Contacts'), self.main_window)
192 view.connect('contact-activated', self.map_contact, fb2c)
193 dialog.vbox.add(view)
195 dialog.vbox.add(view.get_search())
201 # -----------------------------------------------------------------------
202 def map_contact(self, widget, contact, fb2c):
203 view = MapContact(fb2c.friends, contact)
205 dialog = gtk.Dialog(contact.get_name(), self.main_window)
206 dialog.add_button(_('Update'), gtk.RESPONSE_OK)
207 dialog.vbox.add(view)
209 dialog.vbox.add(view.get_search())
211 result = dialog.run()
213 if result == gtk.RESPONSE_OK:
214 friend = view.get_selected_friend()
216 if friend.get_contact() == contact:
217 hildon.hildon_banner_show_information(self.main_window, '', _("Removing existing mappings is not yet supported"))
218 elif view.contact_mapped:
219 fb2c.update_contact(contact, friend, True, True)
220 widget.add_mapping(friend.get_source())
222 fb2c.update_contact(contact, friend, False, True)
223 widget.add_mapping(friend.get_source())
226 # -----------------------------------------------------------------------
227 def need_auth(self, main = False):
228 """Part of the GUI callback API."""
231 hildon.hildon_banner_show_information(self.main_window, '', _("Need to authenticate via browser"))
233 gobject.idle_add(self.need_auth, True)
236 # -----------------------------------------------------------------------
237 def block_for_auth(self, prompt = False, main = False, lock = None):
238 """Part of the GUI callback API."""
241 note = gtk.Dialog(_('Service authorisation'), self.main_window)
242 note.add_button(_("Validate"), gtk.RESPONSE_OK)
244 input = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
245 input.set_property('is-focus', False)
246 note.set_title(_("Verification code from web browser"))
249 note.vbox.add(gtk.Label(_("\nPress 'Validate' once account has\nbeen authorised in web browser.\n")))
255 if prompt and result == gtk.RESPONSE_OK:
256 print input.get_text()
257 return input.get_text()
263 lock = thread.allocate_lock()
265 gobject.idle_add(self.block_for_auth, prompt, True, lock)
270 # -----------------------------------------------------------------------
271 def progress(self, msg, i, j, main = False):
272 """Part of the GUI callback API."""
276 self.progressbar = gtk.ProgressBar()
277 self.progressnote = gtk.Dialog(_("Initialising connections"), self.main_window)
278 self.progressnote.vbox.add(self.progressbar)
279 hildon.hildon_gtk_window_set_progress_indicator(self.progressnote, 1)
281 self.progressnote.show_all()
284 self.progressnote.set_title(_(msg))
285 hildon.hildon_gtk_window_set_progress_indicator(self.progressnote, 0)
287 self.progressbar.set_fraction(float(i) / float(j))
290 self.progressnote.destroy()
294 gobject.idle_add(self.progress, msg, i, j, True)
297 # -----------------------------------------------------------------------
298 def report_error(self, e, prefs = False):
299 if self.progressnote:
300 self.main_window.set_property('sensitive', True)
301 self.progressnote.destroy()
303 hildon.hildon_banner_show_information(self.main_window, '', e)