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