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