d7aec58c8e64698d1e175efa33e1a993418031ed
[hermes] / package / src / gui.py
1 #!/usr/bin/env python
2
3 import gettext
4 import gtk, gobject
5 import traceback
6 import time
7 import thread
8 import contactview
9 import urllib2
10 import hildon
11 import wimpworks
12 import mapcontact
13 from wimpworks import WimpWorks
14 from hermes import Hermes
15
16 class HermesGUI(WimpWorks):
17   """Provides the GUI for Hermes, allowing the syncing of Facebook and
18      Twitter friends' information with the Evolution contacts' database.
19        
20      Copyright (c) Andrew Flegg <andrew@bleb.org> 2009.
21      Released under the Artistic Licence."""
22
23
24   # -----------------------------------------------------------------------
25   def __init__(self):
26     gettext.install('hermes','/opt/hermes/share/locale/')
27     WimpWorks.__init__(self, 'Hermes', version = '0.2.0', dbus_name = 'org.maemo.hermes')
28     self.set_background('background.png')
29     
30     layout = wimpworks.HildonMainScreenLayout(offset = 0.8, container = self)
31     layout.add_button('Retrieve', _("Get contacts' missing info"))
32     layout.add_button('Refresh', _("Update contacts' info"))
33
34     self.add_menu_action("Accounts")
35     self.menu.show_all()
36
37   
38   # -----------------------------------------------------------------------
39   def do_retrieve(self, widget):
40     self.sync(widget, False)
41     
42     
43   # -----------------------------------------------------------------------
44   def do_refresh(self, widget):
45     self.sync(widget, True)
46
47
48   # -----------------------------------------------------------------------
49   def do_accounts(self, widget = None):
50     dialog = gtk.Dialog(_('Accounts'), self.main_window)
51     dialog.add_button(_('Save'), gtk.RESPONSE_OK)
52
53     #pa = hildon.PannableArea()
54     #dialog.vbox.add(pa)
55     content = dialog.vbox 
56     #content = gtk.VBox()
57     #pa.add(content)
58     #pa.set_size_request(600, 380)
59
60     use_facebook = self.new_checkbox(_('Use Facebook'), content)
61     use_facebook.set_active(self.get_use_facebook())
62
63     indent = self.new_indent(content)
64     self.link_control(use_facebook, gtk.Label(_('Note: authentication via web page')), indent)
65     
66     fb_empty = self.link_control(use_facebook, self.new_checkbox(_('Create birthday-only contacts')), indent)
67     fb_empty.set_active(self.get_create_empty())
68
69     use_twitter = self.new_checkbox(_('Use Twitter'), content)
70     use_twitter.set_active(self.get_use_twitter())
71
72     indent = self.new_indent(content)
73     tw_user = self.link_control(use_twitter, self.new_input(_('Twitter username')), indent)
74     tw_user.set_text(self.get_twitter_credentials()[0])
75
76     tw_pass = self.link_control(use_twitter, self.new_input(_('Twitter password'), password = True), indent)
77     tw_pass.set_text(self.get_twitter_credentials()[1])
78
79     dialog.show_all()
80     result = dialog.run()
81     dialog.hide()
82     if result == gtk.RESPONSE_OK:
83       self.set_use_facebook(use_facebook.get_active())
84       self.set_create_empty(fb_empty.get_active())
85       self.set_use_twitter(use_twitter.get_active(), tw_user.get_text(), tw_pass.get_text())
86
87     return result
88    
89
90   # -----------------------------------------------------------------------
91   def sync(self, widget, force, main = True):
92     if main and not self.get_use_facebook() and not self.get_use_twitter():
93       saved = self.do_accounts()
94       if saved == gtk.RESPONSE_DELETE_EVENT:
95         return
96
97     if main:
98       self.main_window.set_property('sensitive', False)
99       thread.start_new_thread(self.sync, (widget, force, False))
100     else:
101       try:
102         fb2c = Hermes(self,
103                       twitter = (self.get_use_twitter() and self.get_twitter_credentials()) or None,
104                       facebook = self.get_use_facebook(),
105                       empty = self.get_create_empty())
106         fb2c.load_friends()
107         fb2c.sync_contacts(resync = force)
108         gobject.idle_add(self.open_summary, fb2c)
109
110       except urllib2.HTTPError, e:
111         traceback.print_exc()
112         if e.code == 401:
113           gobject.idle_add(self.report_error, _('Authentication problem. Check credentials.'), True)
114         else:
115           gobject.idle_add(self.report_error, _('Network connection error. Check connectivity.'))
116
117       except urllib2.URLError, e:
118         traceback.print_exc()
119         gobject.idle_add(self.report_error, _('Network connection error. Check connectivity.'))
120       
121       except Exception, e:
122         traceback.print_exc()
123         gobject.idle_add(self.report_error, _('Something went wrong: ') + e.message)
124
125
126   # -----------------------------------------------------------------------
127   def open_summary(self, fb2c):
128     gobject.idle_add(self.main_window.set_property, 'sensitive', True)
129
130     dialog = gtk.Dialog(_('Summary'), self.main_window)
131     dialog.add_button(_('Done'), gtk.RESPONSE_OK)
132     
133     button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL,
134                            title = _('Updated %d contacts') % (len(fb2c.updated)))
135     button.connect('clicked', self.show_contacts, fb2c, fb2c.updated)
136     button.set_property('sensitive', len(fb2c.updated) > 0)
137     dialog.vbox.add(button)
138     
139     button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL,
140                            title = _('Matched %d contacts') % (len(fb2c.matched)))
141     button.connect('clicked', self.show_contacts, fb2c, fb2c.matched)
142     button.set_property('sensitive', len(fb2c.matched) > 0)
143     dialog.vbox.add(button)
144     
145     button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL,
146                            title = _('%d contacts unmatched') % (len(fb2c.unmatched)))
147     button.connect('clicked', self.show_contacts, fb2c, fb2c.unmatched)
148     button.set_property('sensitive', len(fb2c.unmatched) > 0)
149     dialog.vbox.add(button)
150     
151     dialog.show_all()
152     dialog.run()
153     dialog.hide()
154   
155
156   # -----------------------------------------------------------------------
157   def show_contacts(self, widget, fb2c, contacts):
158     view = contactview.ContactView(contacts)
159
160     dialog = gtk.Dialog(_('Contacts'), self.main_window)
161     view.connect('contact-activated', self.map_contact, fb2c)
162     dialog.vbox.add(view)
163     dialog.show_all()
164     
165     dialog.run()
166     dialog.hide()
167     
168     
169   # -----------------------------------------------------------------------
170   def map_contact(self, widget, contact, fb2c):
171     view = mapcontact.MapContact(fb2c.friends, contact)
172
173     dialog = gtk.Dialog(contact.get_name(), self.main_window)
174     dialog.add_button(_('Update'), gtk.RESPONSE_OK)
175     dialog.vbox.add(view)
176     dialog.show_all()
177     
178     result = dialog.run()
179     dialog.hide()
180     if result == gtk.RESPONSE_OK:
181       friend = view.get_selected_friend()
182       if friend:
183         if 'contact' in friend and friend['contact'] == contact:
184           hildon.hildon_banner_show_information(self.main_window, '', _("Removing existing mappings is not yet supported"))
185         elif view.contact_mapped:
186           if fb2c.update_contact(contact, friend, True):
187             fb2c.addresses.commit_contact(contact)
188         else:
189           if fb2c.update_contact(contact, friend, False):
190             fb2c.addresses.commit_contact(contact)
191
192     
193   # -----------------------------------------------------------------------
194   def need_auth(self, main = False):
195     if main:
196       hildon.hildon_banner_show_information(self.main_window, '', _("Need to authenticate with Facebook"))
197     else:
198       gobject.idle_add(self.need_auth, True)
199     
200
201   # -----------------------------------------------------------------------
202   def block_for_auth(self, main = False, lock = None):
203     if main:
204       note = gtk.Dialog(_('Facebook authorisation'), self.main_window)
205       note.add_button(_("Validate"), gtk.RESPONSE_OK)
206       note.vbox.add(gtk.Label(_("\nPress 'Validate' once Facebook has\nbeen authenticated in web browser.\n")))
207
208       note.show_all()
209       result = note.run()
210       note.hide()
211       lock.release()
212       
213     else:
214       time.sleep(2)
215       lock = thread.allocate_lock()
216       lock.acquire()
217       gobject.idle_add(self.block_for_auth, True, lock)
218       lock.acquire()
219       lock.release()
220
221
222   # -----------------------------------------------------------------------
223   def progress(self, i, j, main = False):
224     if main:
225       if i == 0:
226         self.progressbar = gtk.ProgressBar()
227         self.progressnote = gtk.Dialog(_("Fetching friends' info"), self.main_window)
228         self.progressnote.vbox.add(self.progressbar)
229         hildon.hildon_gtk_window_set_progress_indicator(self.progressnote, 1)
230         
231         self.progressnote.show_all()
232         
233       elif i < j:
234         if i == 1:
235           self.progressnote.set_title(_("Updating contacts"))
236           hildon.hildon_gtk_window_set_progress_indicator(self.progressnote, 0)
237           
238         self.progressbar.set_fraction(float(i) / float(j))
239         
240       else:
241         self.progressnote.destroy()
242         
243       print i,j
244     else:
245       gobject.idle_add(self.progress, i, j, True)
246
247
248   # -----------------------------------------------------------------------
249   def report_error(self, e, prefs = False):
250     if self.progressnote:
251       self.main_window.set_property('sensitive', True)
252       self.progressnote.destroy()
253
254     hildon.hildon_banner_show_information(self.main_window, '', e)
255     if prefs:
256       self.do_accounts()
257
258       
259   def get_use_facebook(self):
260     return self.gconf.get_bool("/apps/maemo/hermes/use_facebook")
261
262
263   def set_use_facebook(self, value):
264     self.gconf.set_bool("/apps/maemo/hermes/use_facebook", value)
265
266   def get_create_empty(self):
267     return self.gconf.get_bool("/apps/maemo/hermes/create_empty")
268
269
270   def set_create_empty(self, value):
271     self.gconf.set_bool("/apps/maemo/hermes/create_empty", value)
272
273
274   def get_use_twitter(self):
275     return self.gconf.get_bool("/apps/maemo/hermes/use_twitter")
276
277
278   def set_use_twitter(self, value, user, password):
279     self.gconf.set_bool("/apps/maemo/hermes/use_twitter", value)
280     self.gconf.set_string("/apps/maemo/hermes/twitter_user", user)
281     self.gconf.set_string("/apps/maemo/hermes/twitter_pwd", password)
282     
283   
284   def get_twitter_credentials(self):
285     return (self.gconf.get_string("/apps/maemo/hermes/twitter_user") or '',
286             self.gconf.get_string("/apps/maemo/hermes/twitter_pwd") or '')
287
288
289 # -------------------------------------------------------------------------
290 if __name__ == '__main__':
291   gui = HermesGUI()
292   gui.run()
293