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
17 class HermesGUI(WimpWorks):
18 """Provides the GUI for Hermes, allowing the syncing of Facebook and
19 Twitter friends' information with the Evolution contacts' database.
21 Copyright (c) Andrew Flegg <andrew@bleb.org> 2009.
22 Released under the Artistic Licence."""
25 # -----------------------------------------------------------------------
26 def __init__(self, providers = None):
27 gettext.install('hermes','/opt/hermes/share/locale/')
28 WimpWorks.__init__(self, 'Hermes', version = '0.8.6', dbus_name = 'org.maemo.hermes')
29 self.set_background('background.png')
31 layout = HildonMainScreenLayout(offset = 0.8, container = self)
32 layout.add_button('Retrieve', _("Get contacts' missing info"))
33 layout.add_button('Refresh', _("Update contacts' info"))
35 self.add_menu_action("Accounts")
36 self.add_menu_action("About")
39 self.providers = providers
40 self.progressnote = None
41 connection = conic.Connection()
42 gobject.timeout_add(100, connection.request_connection, conic.CONNECT_FLAG_NONE)
45 # -----------------------------------------------------------------------
46 def do_retrieve(self, widget):
47 self.sync(widget, False)
50 # -----------------------------------------------------------------------
51 def do_refresh(self, widget):
52 self.sync(widget, True)
55 # -----------------------------------------------------------------------
56 def do_accounts(self, widget = None):
57 dialog = AccountsDialogue(self.main_window, self.providers)
61 # -----------------------------------------------------------------------
62 def do_about(self, widget):
63 """Inspired by HeAboutDialog Python port:
64 http://wiki.maemo.org/Hildon-Extras#HeAboutDialog"""
66 dlg = gtk.Dialog(_("About"), self.main_window)
69 icon.set_from_icon_name(self.name.lower(), gtk.ICON_SIZE_DIALOG)
70 icon.set_padding(5, 5)
72 name = gtk.Label(self.name)
73 name.set_alignment(0, 1)
74 hildon.hildon_helper_set_logical_font(name, 'X-LargeSystemFont')
76 version = gtk.Label('v%s' % (self.version))
77 version.set_alignment(0, 1)
78 version.set_padding(10, 0)
79 hildon.hildon_helper_set_logical_font(version, 'LargeSystemFont')
81 desc = gtk.Label(_("Enrich contacts' from social networks."))
82 desc.set_alignment(0, 0)
84 copy = gtk.Label("Copyright (c) 2010 Andrew Flegg, Fredrik Wendt, Tim Samoff")
85 copy.set_alignment(0, 1)
86 copy.set_padding(0, 5)
87 hildon.hildon_helper_set_logical_font(copy, 'SmallSystemFont')
88 hildon.hildon_helper_set_logical_color(copy, gtk.RC_FG, gtk.STATE_NORMAL, "SecondaryTextColor")
90 layout = gtk.Table(3, 3, False)
91 layout.attach(icon, 0, 1, 0, 2, 0, gtk.EXPAND, 0, 0)
92 layout.attach(name, 1, 2, 0, 1, 0, gtk.EXPAND | gtk.FILL, 0, 0)
93 layout.attach(version, 2, 3, 0, 1, gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL, 0, 0)
94 layout.attach(desc, 1, 3, 1, 2, gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL, 0, 0)
95 layout.attach(copy, 0, 3, 2, 3, gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL, 0, 0)
98 dlg.add_button(_('Visit website'), gtk.RESPONSE_APPLY)
99 dlg.add_button(_('Report bug'), gtk.RESPONSE_NO)
102 if response == gtk.RESPONSE_APPLY:
103 webbrowser.open('http://hermes.garage.maemo.org/')
104 elif response == gtk.RESPONSE_NO:
105 webbrowser.open('https://bugs.maemo.org/enter_bug.cgi?product=Hermes')
109 # -----------------------------------------------------------------------
110 def sync(self, widget, force, main = True):
112 for provider in self.providers:
113 if self.gconf.get_bool('/apps/maemo/hermes/use_%s' % (provider.get_id())):
114 enabled.append(provider)
116 if main and len(enabled) == 0:
117 saved = self.do_accounts()
118 if saved == gtk.RESPONSE_DELETE_EVENT:
121 print "doing sync", main
124 self.main_window.set_property('sensitive', False)
125 thread.start_new_thread(self.sync, (widget, force, False))
128 self.progress('', 0, 0)
130 for provider in enabled:
131 services.append(provider.service(self))
133 hermes = Hermes(services, self.progress)
135 gobject.idle_add(self.open_summary, hermes)
137 except urllib2.HTTPError, e:
138 traceback.print_exc()
140 gobject.idle_add(self.report_error, _('Authentication problem. Check credentials.'), True)
142 gobject.idle_add(self.report_error, _('Network connection error. Check connectivity.'))
144 except urllib2.URLError, e:
145 traceback.print_exc()
146 gobject.idle_add(self.report_error, _('Network connection error. Check connectivity.'))
149 traceback.print_exc()
150 gobject.idle_add(self.report_error, _('Something went wrong: ') + e.message)
153 # -----------------------------------------------------------------------
154 def open_summary(self, fb2c):
155 gobject.idle_add(self.main_window.set_property, 'sensitive', True)
157 dialog = gtk.Dialog(_('Summary'), self.main_window)
158 dialog.add_button(_('Done'), gtk.RESPONSE_OK)
160 button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL,
161 title = _('Updated %d contacts') % (len(fb2c.updated)))
162 button.connect('clicked', self.show_contacts, fb2c, fb2c.updated)
163 button.set_property('sensitive', len(fb2c.updated) > 0)
164 dialog.vbox.add(button)
166 button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL,
167 title = _('Matched %d contacts') % (len(fb2c.matched)))
168 button.connect('clicked', self.show_contacts, fb2c, fb2c.matched)
169 button.set_property('sensitive', len(fb2c.matched) > 0)
170 dialog.vbox.add(button)
172 button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL,
173 title = _('%d contacts unmatched') % (len(fb2c.unmatched)))
174 button.connect('clicked', self.show_contacts, fb2c, fb2c.unmatched)
175 button.set_property('sensitive', len(fb2c.unmatched) > 0)
176 dialog.vbox.add(button)
183 # -----------------------------------------------------------------------
184 def show_contacts(self, widget, fb2c, contacts):
185 view = ContactView(contacts)
187 dialog = gtk.Dialog(_('Contacts'), self.main_window)
188 view.connect('contact-activated', self.map_contact, fb2c)
189 dialog.vbox.add(view)
191 dialog.vbox.add(view.get_search())
197 # -----------------------------------------------------------------------
198 def map_contact(self, widget, contact, fb2c):
199 view = MapContact(fb2c.friends, contact)
201 dialog = gtk.Dialog(contact.get_name(), self.main_window)
202 dialog.add_button(_('Update'), gtk.RESPONSE_OK)
203 dialog.vbox.add(view)
205 dialog.vbox.add(view.get_search())
207 result = dialog.run()
209 if result == gtk.RESPONSE_OK:
210 friend = view.get_selected_friend()
212 if friend.get_contact() == contact:
213 hildon.hildon_banner_show_information(self.main_window, '', _("Removing existing mappings is not yet supported"))
214 elif view.contact_mapped:
215 fb2c.update_contact(contact, friend, True, True)
216 widget.add_mapping(friend.get_source())
218 fb2c.update_contact(contact, friend, False, True)
219 widget.add_mapping(friend.get_source())
222 # -----------------------------------------------------------------------
223 def need_auth(self, main = False):
224 """Part of the GUI callback API."""
227 hildon.hildon_banner_show_information(self.main_window, '', _("Need to authenticate via browser"))
229 gobject.idle_add(self.need_auth, True)
232 # -----------------------------------------------------------------------
233 def block_for_auth(self, prompt = False, main = False, lock = None):
234 """Part of the GUI callback API."""
237 note = gtk.Dialog(_('Service authorisation'), self.main_window)
238 note.add_button(_("Validate"), gtk.RESPONSE_OK)
240 input = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
241 input.set_property('is-focus', False)
242 note.set_title(_("Verification code from web browser"))
245 note.vbox.add(gtk.Label(_("\nPress 'Validate' once account has\nbeen authorised in web browser.\n")))
251 if prompt and result == gtk.RESPONSE_OK:
252 print input.get_text()
253 return input.get_text()
259 lock = thread.allocate_lock()
261 gobject.idle_add(self.block_for_auth, prompt, True, lock)
266 # -----------------------------------------------------------------------
267 def progress(self, msg, i, j, main = False):
268 """Part of the GUI callback API."""
272 self.progressbar = gtk.ProgressBar()
273 self.progressnote = gtk.Dialog(_("Initialising connections"), self.main_window)
274 self.progressnote.vbox.add(self.progressbar)
275 hildon.hildon_gtk_window_set_progress_indicator(self.progressnote, 1)
277 self.progressnote.show_all()
280 self.progressnote.set_title(_(msg))
281 hildon.hildon_gtk_window_set_progress_indicator(self.progressnote, 0)
283 self.progressbar.set_fraction(float(i) / float(j))
286 self.progressnote.destroy()
290 gobject.idle_add(self.progress, msg, i, j, True)
293 # -----------------------------------------------------------------------
294 def report_error(self, e, prefs = False):
295 if self.progressnote:
296 self.main_window.set_property('sensitive', True)
297 self.progressnote.destroy()
299 hildon.hildon_banner_show_information(self.main_window, '', e)