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