Change the block_for_auth API so that an argument can be passed
[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 hermes import Hermes ### FIXME This needs to be new
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                 print services
79                 class FakeContact():
80                     def get_name(self):
81                         return "Fredrik Wendt"
82                     def get_emails(self):
83                         return ["fredrik@wendt.se","maemohermes@wendt.se"]
84                 self._sync_job = SyncJob(services, [FakeContact()], self.progress)
85                 self._sync_job.run()
86                 self._sync_job.get_unmatched_friends()
87                 self._sync_job.get_updated_contacts()
88                 self._sync_job.get_matched_contacts()
89                 raise Exception("TODO - implement syncing")
90         
91             except urllib2.HTTPError, e:
92                 traceback.print_exc()
93                 if e.code == 401:
94                     gobject.idle_add(self.report_error, _('Authentication problem. Check credentials.'), True)
95                 else:
96                     gobject.idle_add(self.report_error, _('Network connection error. Check connectivity.'))
97         
98             except urllib2.URLError, e:
99                 traceback.print_exc()
100                 gobject.idle_add(self.report_error, _('Network connection error. Check connectivity.'))
101           
102             except Exception, e:
103                 traceback.print_exc()
104                 gobject.idle_add(self.report_error, _('Something went wrong: ') + e.message)
105     
106     
107     # -----------------------------------------------------------------------
108     def open_summary(self, fb2c):
109         gobject.idle_add(self.main_window.set_property, 'sensitive', True)
110     
111         dialog = gtk.Dialog(_('Summary'), self.main_window)
112         dialog.add_button(_('Done'), gtk.RESPONSE_OK)
113       
114         button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL,
115                                title = _('Updated %d contacts') % (len(fb2c.updated)))
116         button.connect('clicked', self.show_contacts, fb2c, fb2c.updated)
117         button.set_property('sensitive', len(fb2c.updated) > 0)
118         dialog.vbox.add(button)
119         
120         button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL,
121                                title = _('Matched %d contacts') % (len(fb2c.matched)))
122         button.connect('clicked', self.show_contacts, fb2c, fb2c.matched)
123         button.set_property('sensitive', len(fb2c.matched) > 0)
124         dialog.vbox.add(button)
125       
126         button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL,
127                                title = _('%d contacts unmatched') % (len(fb2c.unmatched)))
128         button.connect('clicked', self.show_contacts, fb2c, fb2c.unmatched)
129         button.set_property('sensitive', len(fb2c.unmatched) > 0)
130         dialog.vbox.add(button)
131       
132         dialog.show_all()
133         dialog.run()
134         dialog.hide()
135     
136     
137     # -----------------------------------------------------------------------
138     def show_contacts(self, widget, fb2c, contacts):
139         view = ContactView(contacts)
140     
141         dialog = gtk.Dialog(_('Contacts'), self.main_window)
142         view.connect('contact-activated', self.map_contact, fb2c)
143         dialog.vbox.add(view)
144         dialog.show_all()
145       
146         dialog.run()
147         dialog.hide()
148       
149       
150     # -----------------------------------------------------------------------
151     def map_contact(self, widget, contact, fb2c):
152         view = MapContact(fb2c.friends, contact)
153     
154         dialog = gtk.Dialog(contact.get_name(), self.main_window)
155         dialog.add_button(_('Update'), gtk.RESPONSE_OK)
156         dialog.vbox.add(view)
157         dialog.show_all()
158       
159         result = dialog.run()
160         dialog.hide()
161         if result == gtk.RESPONSE_OK:
162             friend = view.get_selected_friend()
163             if friend:
164                 if 'contact' in friend and friend['contact'] == contact:
165                     hildon.hildon_banner_show_information(self.main_window, '', _("Removing existing mappings is not yet supported"))
166                 elif view.contact_mapped:
167                     if fb2c.update_contact(contact, friend, True):
168                         fb2c.addresses.commit_contact(contact)
169                 else:
170                     if fb2c.update_contact(contact, friend, False):
171                         fb2c.addresses.commit_contact(contact)
172     
173                         
174     # -----------------------------------------------------------------------
175     def need_auth(self, main = False):
176         """Part of the GUI callback API."""
177         
178         if main:
179             hildon.hildon_banner_show_information(self.main_window, '', _("Need to authenticate via browser"))
180         else:
181             gobject.idle_add(self.need_auth, True)
182       
183     
184     # -----------------------------------------------------------------------
185     def block_for_auth(self, prompt = False, main = False, lock = None):
186         """Part of the GUI callback API."""
187
188         if main:
189             note = gtk.Dialog(_('Service authorisation'), self.main_window)
190             note.add_button(_("Validate"), gtk.RESPONSE_OK)
191             if prompt:
192                 input = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
193                 input.set_placeholder(_("Verification code from web browser"))
194                 input.set_property('is-focus', False)
195                 note.vbox.add(input)
196             else:
197                 note.vbox.add(gtk.Label(_("\nPress 'Validate' once account has\nbeen authorised in web browser.\n")))
198     
199             note.show_all()
200             result = note.run()
201             note.hide()
202             lock.release()
203             if prompt and result == gtk.RESPONSE_OK:
204                 return input.get_text()
205             else:
206                 return None
207         
208         else:
209             time.sleep(2)
210             lock = thread.allocate_lock()
211             lock.acquire()
212             gobject.idle_add(self.block_for_auth, prompt, True, lock)
213             lock.acquire()
214             lock.release()
215                       
216                         
217     # -----------------------------------------------------------------------
218     def progress(self, i, j, main = False):
219         """Part of the GUI callback API."""
220
221         if main:
222             if i == 0:
223                 self.progressbar = gtk.ProgressBar()
224                 self.progressnote = gtk.Dialog(_("Fetching friends' info"), self.main_window)
225                 self.progressnote.vbox.add(self.progressbar)
226                 hildon.hildon_gtk_window_set_progress_indicator(self.progressnote, 1)
227                
228                 self.progressnote.show_all()
229               
230             elif i < j:
231                 if i == 1:
232                     self.progressnote.set_title(_("Updating contacts"))
233                     hildon.hildon_gtk_window_set_progress_indicator(self.progressnote, 0)
234                 
235                 self.progressbar.set_fraction(float(i) / float(j))
236               
237             else:
238                 self.progressnote.destroy()
239               
240             print i,j
241         else:
242             gobject.idle_add(self.progress, i, j, True)
243
244        
245     # -----------------------------------------------------------------------
246     def report_error(self, e, prefs = False):
247         if self.progressnote:
248             self.main_window.set_property('sensitive', True)
249             self.progressnote.destroy()
250     
251         hildon.hildon_banner_show_information(self.main_window, '', e)
252         if prefs:
253             self.do_accounts()