Dependency inject service ID, so that it can be stamped on friends and
[hermes] / package / src / org / maemo / hermes / gui / gtkui.py
1 import gettext
2 import gtk, gobject
3 import traceback
4 import time
5 import thread
6 import urllib2
7 import hildon
8 from org.bleb.wimpworks import WimpWorks
9 from org.maemo.hermes.gui.contactview import ContactView
10 from org.maemo.hermes.gui.mapcontact import MapContact
11 from org.maemo.hermes.gui.accountsdialogue import AccountsDialogue
12 from org.bleb.wimpworks import HildonMainScreenLayout
13 from org.maemo.hermes.engine.syncjob import SyncJob
14 from org.maemo.hermes.engine.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, providers = None):
26         gettext.install('hermes','/opt/hermes/share/locale/')
27         WimpWorks.__init__(self, 'Hermes', version = '0.9.0', dbus_name = 'org.maemo.hermes')
28         self.set_background('background.png')
29         
30         layout = 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         self.providers = providers
38         self.progressnote = None
39
40   
41     # -----------------------------------------------------------------------
42     def do_retrieve(self, widget):
43         self.sync(widget, False)
44     
45     
46     # -----------------------------------------------------------------------
47     def do_refresh(self, widget):
48         self.sync(widget, True)
49
50
51     # -----------------------------------------------------------------------
52     def do_accounts(self, widget = None):
53         dialog = AccountsDialogue(self.main_window, self.providers)
54         dialog.show()
55    
56
57     # -----------------------------------------------------------------------
58     def sync(self, widget, force, main = True):
59         enabled = []
60         for provider in self.providers:
61             if self.gconf.get_bool('/apps/maemo/hermes/use_%s' % (provider.get_id())):
62                 enabled.append(provider)
63                 
64         if main and len(enabled) == 0:
65             saved = self.do_accounts()
66             if saved == gtk.RESPONSE_DELETE_EVENT:
67                 return
68         
69         if main:
70             self.main_window.set_property('sensitive', False)
71             thread.start_new_thread(self.sync, (widget, force, False))
72         else:
73             try:
74                 services = []
75                 for provider in enabled:
76                     services.append(provider.service(self))
77                     
78                 hermes = Hermes(services, self.progress)
79                 hermes.run_alt(force)
80                 gobject.idle_add(self.open_summary, hermes)
81         
82             except urllib2.HTTPError, e:
83                 traceback.print_exc()
84                 if e.code == 401:
85                     gobject.idle_add(self.report_error, _('Authentication problem. Check credentials.'), True)
86                 else:
87                     gobject.idle_add(self.report_error, _('Network connection error. Check connectivity.'))
88         
89             except urllib2.URLError, e:
90                 traceback.print_exc()
91                 gobject.idle_add(self.report_error, _('Network connection error. Check connectivity.'))
92           
93             except Exception, e:
94                 traceback.print_exc()
95                 gobject.idle_add(self.report_error, _('Something went wrong: ') + e.message)
96     
97     
98     # -----------------------------------------------------------------------
99     def open_summary(self, fb2c):
100         gobject.idle_add(self.main_window.set_property, 'sensitive', True)
101     
102         dialog = gtk.Dialog(_('Summary'), self.main_window)
103         dialog.add_button(_('Done'), gtk.RESPONSE_OK)
104       
105         button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL,
106                                title = _('Updated %d contacts') % (len(fb2c.updated)))
107         button.connect('clicked', self.show_contacts, fb2c, fb2c.updated)
108         button.set_property('sensitive', len(fb2c.updated) > 0)
109         dialog.vbox.add(button)
110         
111         button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL,
112                                title = _('Matched %d contacts') % (len(fb2c.matched)))
113         button.connect('clicked', self.show_contacts, fb2c, fb2c.matched)
114         button.set_property('sensitive', len(fb2c.matched) > 0)
115         dialog.vbox.add(button)
116       
117         button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL,
118                                title = _('%d contacts unmatched') % (len(fb2c.unmatched)))
119         button.connect('clicked', self.show_contacts, fb2c, fb2c.unmatched)
120         button.set_property('sensitive', len(fb2c.unmatched) > 0)
121         dialog.vbox.add(button)
122       
123         dialog.show_all()
124         dialog.run()
125         dialog.hide()
126     
127     
128     # -----------------------------------------------------------------------
129     def show_contacts(self, widget, fb2c, contacts):
130         view = ContactView(contacts)
131     
132         dialog = gtk.Dialog(_('Contacts'), self.main_window)
133         view.connect('contact-activated', self.map_contact, fb2c)
134         dialog.vbox.add(view)
135         dialog.show_all()
136       
137         dialog.run()
138         dialog.hide()
139       
140       
141     # -----------------------------------------------------------------------
142     def map_contact(self, widget, contact, fb2c):
143         view = MapContact(fb2c.friends, contact)
144     
145         dialog = gtk.Dialog(contact.get_name(), self.main_window)
146         dialog.add_button(_('Update'), gtk.RESPONSE_OK)
147         dialog.vbox.add(view)
148         dialog.show_all()
149       
150         result = dialog.run()
151         dialog.hide()
152         if result == gtk.RESPONSE_OK:
153             friend = view.get_selected_friend()
154             if friend:
155                 if 'contact' in friend and friend['contact'] == contact:
156                     hildon.hildon_banner_show_information(self.main_window, '', _("Removing existing mappings is not yet supported"))
157                 elif view.contact_mapped:
158                     if fb2c.update_contact(contact, friend, True):
159                         fb2c.addresses.commit_contact(contact)
160                 else:
161                     if fb2c.update_contact(contact, friend, False):
162                         fb2c.addresses.commit_contact(contact)
163     
164                         
165     # -----------------------------------------------------------------------
166     def need_auth(self, main = False):
167         """Part of the GUI callback API."""
168         
169         if main:
170             hildon.hildon_banner_show_information(self.main_window, '', _("Need to authenticate via browser"))
171         else:
172             gobject.idle_add(self.need_auth, True)
173       
174     
175     # -----------------------------------------------------------------------
176     def block_for_auth(self, prompt = False, main = False, lock = None):
177         """Part of the GUI callback API."""
178
179         if main:
180             note = gtk.Dialog(_('Service authorisation'), self.main_window)
181             note.add_button(_("Validate"), gtk.RESPONSE_OK)
182             if prompt:
183                 input = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
184                 input.set_property('is-focus', False)
185                 note.set_title(_("Verification code from web browser"))
186                 note.vbox.add(input)
187             else:
188                 note.vbox.add(gtk.Label(_("\nPress 'Validate' once account has\nbeen authorised in web browser.\n")))
189     
190             note.show_all()
191             result = note.run()
192             note.hide()
193             lock.release()
194             if prompt and result == gtk.RESPONSE_OK:
195                 print input.get_text()
196                 return input.get_text()
197             else:
198                 return None
199         
200         else:
201             time.sleep(2)
202             lock = thread.allocate_lock()
203             lock.acquire()
204             gobject.idle_add(self.block_for_auth, prompt, True, lock)
205             lock.acquire()
206             lock.release()
207                       
208                         
209     # -----------------------------------------------------------------------
210     def progress(self, i, j, main = False):
211         """Part of the GUI callback API."""
212
213         if main:
214             if i == 0:
215                 self.progressbar = gtk.ProgressBar()
216                 self.progressnote = gtk.Dialog(_("Fetching friends' info"), self.main_window)
217                 self.progressnote.vbox.add(self.progressbar)
218                 hildon.hildon_gtk_window_set_progress_indicator(self.progressnote, 1)
219                
220                 self.progressnote.show_all()
221               
222             elif i < j:
223                 if i == 1:
224                     self.progressnote.set_title(_("Updating contacts"))
225                     hildon.hildon_gtk_window_set_progress_indicator(self.progressnote, 0)
226                 
227                 self.progressbar.set_fraction(float(i) / float(j))
228               
229             else:
230                 self.progressnote.destroy()
231               
232             print i,j
233         else:
234             gobject.idle_add(self.progress, i, j, True)
235
236        
237     # -----------------------------------------------------------------------
238     def report_error(self, e, prefs = False):
239         if self.progressnote:
240             self.main_window.set_property('sensitive', True)
241             self.progressnote.destroy()
242     
243         hildon.hildon_banner_show_information(self.main_window, '', e)
244         if prefs:
245             self.do_accounts()